Elvis 1.4, part 8 of 8
Steve Kirkendall
kirkenda at eecs.cs.pdx.edu
Tue Dec 4 08:36:52 AEST 1990
# --------------------------- cut here ----------------------------
# This is a shar archive. To unpack it, save it to a file, and delete
# anything above the "cut here" line. Then run sh on the file.
#
# -rw-r--r-- 1 kirkenda 7638 Dec 2 17:57 refont.c
# -rw-r--r-- 1 kirkenda 2957 Dec 2 17:57 vars.c
# -rw-r--r-- 1 kirkenda 13459 Dec 2 17:57 vcmd.c
# -rw-r--r-- 1 kirkenda 20322 Dec 2 17:57 vi.c
# -rw-r--r-- 1 kirkenda 18110 Dec 2 17:57 vi.h
#
if test -f vars.c -a "$1" != -f
then
echo Will not overwrite vars.c
else
echo Extracting vars.c
sed 's/^X//' >vars.c <<\eof
X/* vars.c */
X
X/* Author:
X * Steve Kirkendall
X * 14407 SW Teal Blvd. #C
X * Beaverton, OR 97005
X * kirkenda at cs.pdx.edu
X */
X
X
X/* This file contains variables which weren't happy anyplace else */
X
X#include "config.h"
X#include "vi.h"
X
X/*------------------------------------------------------------------------*/
X
X/* used to remember whether the file has been modified */
Xstruct _viflags viflags;
X
X/* used to access the tmp file */
Xlong lnum[MAXBLKS];
Xlong nlines;
Xint tmpfd = -1;
X
X/* used to keep track of the current file & alternate file */
Xlong origtime;
Xchar origname[256];
Xchar prevorig[256];
Xlong prevline = 1;
X
X/* used to track various places in the text */
XMARK mark[NMARKS]; /* marks 'a through 'z, plus mark '' */
XMARK cursor; /* the cursor position within the file */
X
X/* which mode of the editor we're in */
Xint mode; /* vi mode? ex mode? quitting? */
X
X/* used to manage the args list */
Xchar args[BLKSIZE]; /* list of filenames to edit */
Xint argno; /* index of current file in args list */
Xint nargs; /* number of filenames in args[] */
X
X/* dummy var, never explicitly referenced */
Xint bavar; /* used only in BeforeAfter macros */
X
X/* have we made a multi-line change? */
Xint mustredraw; /* must we redraw the whole screen? */
X
X/* used to detect changes that invalidate cached text/blocks */
Xlong changes; /* incremented when file is changed */
Xint significant; /* boolean: was a *REAL* change made? */
X
X/* used to support the pfetch() macro */
Xint plen; /* length of the line */
Xlong pline; /* line number that len refers to */
Xlong pchgs; /* "changes" level that len refers to */
Xchar *ptext; /* text of previous line, if valid */
X
X/* misc temporary storage - mostly for strings */
XBLK tmpblk; /* a block used to accumulate changes */
X
X/* screen oriented stuff */
Xlong topline; /* file line number of top line */
Xint leftcol; /* column number of left col */
Xint physcol; /* physical column number that cursor is on */
Xint physrow; /* physical row number that cursor is on */
X
X/* used to help minimize that "[Hit a key to continue]" message */
Xint exwrote; /* Boolean: was the last ex command wordy? */
X
X/* This variable affects the behaviour of certain functions -- most importantly
X * the input function.
X */
Xint doingdot; /* boolean: are we doing the "." command? */
X
X/* This variable affects the behaviour of the ":s" command, and it is also
X * used to detect & prohibit nesting of ":g" commands
X */
Xint doingglobal; /* boolean: are doing a ":g" command? */
X/* These are used for reporting multi-line changes to the user */
Xlong rptlines; /* number of lines affected by a command */
Xchar *rptlabel; /* description of how lines were affected */
X
X/* These store info that pertains to the shift-U command */
Xlong U_line; /* line# of the undoable line, or 0l for none */
Xchar U_text[BLKSIZE]; /* contents of the undoable line */
X
X/* Bigger stack req'ed for TOS */
X
X#if TOS
Xlong _stksize = 16384;
X#endif
eof
if test `wc -c <vars.c` -ne 2957
then
echo vars.c damaged!
fi
fi
if test -f vcmd.c -a "$1" != -f
then
echo Will not overwrite vcmd.c
else
echo Extracting vcmd.c
sed 's/^X//' >vcmd.c <<\eof
X/* vcmd.c */
X
X/* Author:
X * Steve Kirkendall
X * 14407 SW Teal Blvd. #C
X * Beaverton, OR 97005
X * kirkenda at cs.pdx.edu
X */
X
X
X/* This file contains the functions that handle VI commands */
X
X
X#include "config.h"
X#include "vi.h"
X#if MSDOS
X#include <process.h>
X#include <string.h>
X#endif
X#if TOS
X#include <osbind.h>
X#include <string.h>
X#endif
X#if OSK
X# include <stdio.h>
X#endif
X
X
X/* This function puts the editor in EX mode */
XMARK v_quit()
X{
X move(LINES - 1, 0);
X mode = MODE_EX;
X return cursor;
X}
X
X/* This function causes the screen to be redrawn */
XMARK v_redraw()
X{
X redraw(MARK_UNSET, FALSE);
X return cursor;
X}
X
X/* This function executes a single EX command, and waits for a user keystroke
X * before returning to the VI screen. If that keystroke is another ':', then
X * another EX command is read and executed.
X */
X/*ARGSUSED*/
XMARK v_1ex(m, text)
X MARK m; /* the current line */
X char *text; /* the first command to execute */
X{
X /* run the command. be careful about modes & output */
X exwrote = (mode == MODE_COLON);
X doexcmd(text);
X exrefresh();
X
X /* if mode is no longer MODE_VI, then we should quit right away! */
X if (mode != MODE_VI && mode != MODE_COLON)
X return cursor;
X
X /* The command did some output. Wait for a keystoke. */
X if (exwrote)
X {
X mode = MODE_VI;
X msg("[Hit <RETURN> to continue]");
X if (getkey(0) == ':')
X { mode = MODE_COLON;
X addch('\n');
X }
X else
X redraw(MARK_UNSET, FALSE);
X }
X
X return cursor;
X}
X
X/* This function undoes the last change */
X/*ARGSUSED*/
XMARK v_undo(m)
X MARK m; /* (ignored) */
X{
X if (undo())
X {
X redraw(MARK_UNSET, FALSE);
X }
X return cursor;
X}
X
X/* This function deletes the character(s) that the cursor is on */
XMARK v_xchar(m, cnt, cmd)
X MARK m; /* where to start deletions */
X long cnt; /* number of chars to delete */
X int cmd; /* either 'x' or 'X' */
X{
X DEFAULT(1);
X
X /* for 'X', adjust so chars are deleted *BEFORE* cursor */
X if (cmd == 'X')
X {
X if (markidx(m) < cnt)
X return MARK_UNSET;
X m -= cnt;
X }
X
X /* make sure we don't try to delete more thars than there are */
X pfetch(markline(m));
X if (markidx(m + cnt) > plen)
X {
X cnt = plen - markidx(m);
X }
X if (cnt == 0L)
X {
X return MARK_UNSET;
X }
X
X /* do it */
X ChangeText
X {
X cut(m, m + cnt);
X delete(m, m + cnt);
X }
X return m;
X}
X
X/* This function defines a mark */
X/*ARGSUSED*/
XMARK v_mark(m, count, key)
X MARK m; /* where the mark will be */
X long count; /* (ignored) */
X int key; /* the ASCII label of the mark */
X{
X if (key < 'a' || key > 'z')
X {
X msg("Marks must be from a to z");
X }
X else
X {
X mark[key - 'a'] = m;
X }
X return m;
X}
X
X/* This function toggles upper & lower case letters */
XMARK v_ulcase(m, cnt)
X MARK m; /* where to make the change */
X long cnt; /* number of chars to flip */
X{
X REG char *pos;
X REG int i, j;
X static char flip[] =
X "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ[](){}<>";
X
X DEFAULT(1);
X
X /* fetch the current version of the line */
X pfetch(markline(m));
X
X /* for each position in the line */
X for (j = 0, i = markidx(m); j < cnt && ptext[i]; j++, i++)
X {
X tmpblk.c[j] = 0;
X
X /* one of the standard chars? */
X for (pos = flip; *pos && *pos != ptext[i]; pos++)
X {
X }
X if (*pos)
X {
X tmpblk.c[j] = flip[(int)(pos - flip) ^ 1];
X }
X#ifndef NO_DIGRAPH
X else /* one of the non-standard chars? */
X {
X for (pos = o_flipcase; *pos && *pos != ptext[i]; pos++)
X {
X }
X if (*pos)
X {
X tmpblk.c[j] = o_flipcase[(int)(pos - o_flipcase) ^ 1];
X }
X }
X#endif
X
X /* if nothing special, then don't change it */
X if (tmpblk.c[j] == 0)
X {
X tmpblk.c[j] = ptext[i];
X }
X }
X
X /* if the new text is different from the old, then change it */
X if (strncmp(tmpblk.c, &ptext[markidx(m)], j))
X {
X ChangeText
X {
X tmpblk.c[j] = '\0';
X change(m, m + j, tmpblk.c);
X }
X }
X
X return m + j;
X}
X
X
XMARK v_replace(m, cnt, key)
X MARK m; /* first char to be replaced */
X long cnt; /* number of chars to replace */
X int key; /* what to replace them with */
X{
X REG char *text;
X REG int i;
X
X DEFAULT(1);
X
X /* map ^M to '\n' */
X if (key == '\r')
X {
X key = '\n';
X }
X
X /* make sure the resulting line isn't too long */
X if (cnt > BLKSIZE - 2 - markidx(m))
X {
X cnt = BLKSIZE - 2 - markidx(m);
X }
X
X /* build a string of the desired character with the desired length */
X for (text = tmpblk.c, i = cnt; i > 0; i--)
X {
X *text++ = key;
X }
X *text = '\0';
X
X /* make sure cnt doesn't extend past EOL */
X pfetch(markline(m));
X key = markidx(m);
X if (key + cnt > plen)
X {
X cnt = plen - key;
X }
X
X /* do the replacement */
X ChangeText
X {
X change(m, m + cnt, tmpblk.c);
X }
X
X if (*tmpblk.c == '\n')
X {
X return (m & ~(BLKSIZE - 1)) + cnt * BLKSIZE;
X }
X else
X {
X return m + cnt - 1;
X }
X}
X
XMARK v_overtype(m)
X MARK m; /* where to start overtyping */
X{
X MARK end; /* end of a substitution */
X static long width; /* width of a single-line replace */
X
X /* the "doingdot" version of replace is really a substitution */
X if (doingdot)
X {
X /* was the last one really repeatable? */
X if (width < 0)
X {
X msg("Can't repeat a multi-line overtype command");
X return MARK_UNSET;
X }
X
X /* replacing nothing by nothing? Don't bother */
X if (width == 0)
X {
X return m;
X }
X
X /* replace some chars by repeated text */
X return v_subst(m, width);
X }
X
X /* Normally, we input starting here, in replace mode */
X ChangeText
X {
X end = input(m, m, WHEN_VIREP);
X }
X
X /* if we ended on the same line we started on, then this
X * overtype is repeatable via the dot key.
X */
X if (markline(end) == markline(m) && end >= m - 1L)
X {
X width = end - m + 1L;
X }
X else /* it isn't repeatable */
X {
X width = -1L;
X }
X
X return end;
X}
X
X
X/* This function selects which cut buffer to use */
X/*ARGSUSED*/
XMARK v_selcut(m, cnt, key)
X MARK m;
X long cnt;
X int key;
X{
X cutname(key);
X return m;
X}
X
X/* This function pastes text from a cut buffer */
X/*ARGSUSED*/
XMARK v_paste(m, cnt, cmd)
X MARK m; /* where to paste the text */
X long cnt; /* (ignored) */
X int cmd; /* either 'p' or 'P' */
X{
X ChangeText
X {
X m = paste(m, cmd == 'p', FALSE);
X }
X return m;
X}
X
X/* This function yanks text into a cut buffer */
XMARK v_yank(m, n)
X MARK m, n; /* range of text to yank */
X{
X cut(m, n);
X return m;
X}
X
X/* This function deletes a range of text */
XMARK v_delete(m, n)
X MARK m, n; /* range of text to delete */
X{
X /* illegal to try and delete nothing */
X if (n <= m)
X {
X return MARK_UNSET;
X }
X
X /* Do it */
X ChangeText
X {
X cut(m, n);
X delete(m, n);
X }
X return m;
X}
X
X
X/* This starts input mode without deleting anything */
XMARK v_insert(m, cnt, key)
X MARK m; /* where to start (sort of) */
X long cnt; /* repeat how many times? */
X int key; /* what command is this for? {a,A,i,I,o,O} */
X{
X int wasdot;
X long reps;
X int after; /* are we appending or inserting? */
X
X DEFAULT(1);
X
X ChangeText
X {
X /* tweak the insertion point, based on command key */
X switch (key)
X {
X case 'i':
X after = FALSE;
X break;
X
X case 'a':
X pfetch(markline(m));
X if (plen > 0)
X {
X m++;
X }
X after = TRUE;
X break;
X
X case 'I':
X m = m_front(m, 1L);
X after = FALSE;
X break;
X
X case 'A':
X pfetch(markline(m));
X m = (m & ~(BLKSIZE - 1)) + plen;
X after = TRUE;
X break;
X
X case 'O':
X m &= ~(BLKSIZE - 1);
X add(m, "\n");
X after = FALSE;
X break;
X
X case 'o':
X m = (m & ~(BLKSIZE - 1)) + BLKSIZE;
X add(m, "\n");
X after = FALSE;
X break;
X }
X
X /* insert the same text once or more */
X for (reps = cnt, wasdot = doingdot; reps > 0; reps--, doingdot = TRUE)
X {
X m = input(m, m, WHEN_VIINP);
X if (after)
X {
X m++;
X }
X }
X if (after)
X {
X m--;
X }
X
X doingdot = wasdot;
X }
X
X#ifndef CRUNCH
X# ifndef NO_EXTENSIONS
X if (key == 'i' && *o_inputmode && mode == MODE_VI)
X {
X msg("Now in visual command mode! To return to input mode, hit <i>.");
X }
X# endif
X#endif
X
X return m;
X}
X
X/* This starts input mode with some text deleted */
XMARK v_change(m, n)
X MARK m, n; /* the range of text to change */
X{
X int lnmode; /* is this a line-mode change? */
X
X /* swap them if they're in reverse order */
X if (m > n)
X {
X MARK tmp;
X tmp = m;
X m = n;
X n = tmp;
X }
X
X /* for line mode, retain the last newline char */
X lnmode = (markidx(m) == 0 && markidx(n) == 0 && m != n);
X if (lnmode)
X {
X n -= BLKSIZE;
X pfetch(markline(n));
X n = (n & ~(BLKSIZE - 1)) + plen;
X }
X
X ChangeText
X {
X cut(m, n);
X m = input(m, n, WHEN_VIINP);
X }
X
X return m;
X}
X
X/* This function replaces a given number of characters with input */
XMARK v_subst(m, cnt)
X MARK m; /* where substitutions start */
X long cnt; /* number of chars to replace */
X{
X DEFAULT(1);
X
X /* make sure we don't try replacing past EOL */
X pfetch(markline(m));
X if (markidx(m) + cnt > plen)
X {
X cnt = plen - markidx(m);
X }
X
X /* Go for it! */
X ChangeText
X {
X cut(m, m + cnt);
X m = input(m, m + cnt, WHEN_VIINP);
X }
X return m;
X}
X
X/* This calls the ex "join" command to join some lines together */
XMARK v_join(m, cnt)
X MARK m; /* the first line to be joined */
X long cnt; /* number of other lines to join */
X{
X MARK joint; /* where the lines were joined */
X
X DEFAULT(1);
X
X /* figure out where the joint will be */
X pfetch(markline(m));
X joint = (m & ~(BLKSIZE - 1)) + plen;
X
X /* join the lines */
X cmd_join(m, m + MARK_AT_LINE(cnt), CMD_JOIN, 0, "");
X mustredraw = TRUE;
X
X /* the cursor should be left at the joint */
X return joint;
X}
X
X/* This calls the ex shifter command to shift some lines */
Xstatic MARK shift_help(m, n, excmd)
X MARK m, n; /* range of lines to shift */
X CMD excmd; /* which way do we shift? */
X{
X /* adjust for inclusive endmarks in ex */
X n -= BLKSIZE;
X
X cmd_shift(m, n, excmd, 0, "");
X return m;
X}
X
X/* This calls the ex "<" command to shift some lines left */
XMARK v_lshift(m, n)
X MARK m, n; /* range of lines to shift */
X{
X return shift_help(m, n, CMD_SHIFTL);
X}
X
X/* This calls the ex ">" command to shift some lines right */
XMARK v_rshift(m, n)
X MARK m, n; /* range of lines to shift */
X{
X return shift_help(m, n, CMD_SHIFTR);
X}
X
X/* This runs some lines through a filter program */
XMARK v_filter(m, n)
X MARK m, n; /* range of lines to shift */
X{
X char cmdln[100]; /* a shell command line */
X
X /* adjust for inclusive endmarks in ex */
X n -= BLKSIZE;
X
X if (vgets('!', cmdln, sizeof(cmdln)) > 0)
X {
X filter(m, n, cmdln);
X }
X
X redraw(MARK_UNSET, FALSE);
X return m;
X}
X
X
X/* This function runs the ex "file" command to show the file's status */
XMARK v_status()
X{
X cmd_file(cursor, cursor, CMD_FILE, 0, "");
X return cursor;
X}
X
X
X/* This function runs the ":&" command to repeat the previous :s// */
XMARK v_again(m, n)
X MARK m, n;
X{
X cmd_substitute(m, n - BLKSIZE, CMD_SUBAGAIN, TRUE, "");
X return cursor;
X}
X
X
X
X/* This function switches to the previous file, if possible */
XMARK v_switch()
X{
X if (!*prevorig)
X msg("No previous file");
X else
X { strcpy(tmpblk.c, prevorig);
X cmd_edit(cursor, cursor, CMD_EDIT, 0, tmpblk.c);
X }
X return cursor;
X}
X
X/* This function does a tag search on a keyword */
X/*ARGSUSED*/
XMARK v_tag(keyword, m, cnt)
X char *keyword;
X MARK m;
X long cnt;
X{
X /* move the cursor to the start of the tag name, where m is */
X cursor = m;
X
X /* perform the tag search */
X cmd_tag(cursor, cursor, CMD_TAG, 0, keyword);
X
X return cursor;
X}
X
X#ifndef NO_EXTENSIONS
X/* This function looks up a keyword by calling the helpprog program */
X/*ARGSUSED*/
XMARK v_keyword(keyword, m, cnt)
X char *keyword;
X MARK m;
X long cnt;
X{
X int waswarn;
X char cmdline[130];
X
X move(LINES - 1, 0);
X addstr("---------------------------------------------------------\n");
X clrtoeol();
X refresh();
X sprintf(cmdline, "%s %s", o_keywordprg, keyword);
X waswarn = *o_warn;
X *o_warn = FALSE;
X suspend_curses();
X if (system(cmdline))
X {
X addstr("<<< failed >>>\n");
X }
X resume_curses(FALSE);
X mode = MODE_VI;
X redraw(MARK_UNSET, FALSE);
X *o_warn = waswarn;
X
X return m;
X}
X
X
X
XMARK v_increment(keyword, m, cnt)
X char *keyword;
X MARK m;
X long cnt;
X{
X static sign;
X char newval[12];
X long atol();
X
X DEFAULT(1);
X
X /* get one more keystroke, unless doingdot */
X if (!doingdot)
X {
X sign = getkey(0);
X }
X
X /* adjust the number, based on that second keystroke */
X switch (sign)
X {
X case '+':
X case '#':
X cnt = atol(keyword) + cnt;
X break;
X
X case '-':
X cnt = atol(keyword) - cnt;
X break;
X
X case '=':
X break;
X
X default:
X return MARK_UNSET;
X }
X sprintf(newval, "%ld", cnt);
X
X ChangeText
X {
X change(m, m + strlen(keyword), newval);
X }
X
X return m;
X}
X#endif
X
X
X/* This function acts like the EX command "xit" */
X/*ARGSUSED*/
XMARK v_xit(m, cnt, key)
X MARK m; /* ignored */
X long cnt; /* ignored */
X int key; /* must be a second 'Z' */
X{
X /* if second char wasn't 'Z', fail */
X if (key != 'Z')
X {
X return MARK_UNSET;
X }
X
X /* move the cursor to the bottom of the screen */
X move(LINES - 1, 0);
X clrtoeol();
X
X /* do the xit command */
X cmd_xit(m, m, CMD_XIT, FALSE, "");
X
X /* return the cursor */
X return m;
X}
X
X
X/* This function undoes changes to a single line, if possible */
XMARK v_undoline(m)
X MARK m; /* where we hope to undo the change */
X{
X /* make sure we have the right line in the buffer */
X if (markline(m) != U_line)
X {
X return MARK_UNSET;
X }
X
X /* fix it */
X ChangeText
X {
X strcat(U_text, "\n");
X change(MARK_AT_LINE(U_line), MARK_AT_LINE(U_line + 1), U_text);
X }
X
X /* nothing in the buffer anymore */
X U_line = -1L;
X
X /* return, with the cursor at the front of the line */
X return m & ~(BLKSIZE - 1);
X}
X
X
X#ifndef NO_ERRLIST
XMARK v_errlist(m)
X MARK m;
X{
X cmd_errlist(m, m, CMD_ERRLIST, FALSE, "");
X return cursor;
X}
X#endif
X
X
X#ifndef NO_AT
X/*ARGSUSED*/
XMARK v_at(m, cnt, key)
X MARK m;
X long cnt;
X int key;
X{
X if (!fromcutbuf(key))
X {
X return MARK_UNSET;
X }
X return cursor;
X}
X#endif
eof
if test `wc -c <vcmd.c` -ne 13459
then
echo vcmd.c damaged!
fi
fi
if test -f vi.c -a "$1" != -f
then
echo Will not overwrite vi.c
else
echo Extracting vi.c
sed 's/^X//' >vi.c <<\eof
X/* vi.c */
X
X/* Author:
X * Steve Kirkendall
X * 14407 SW Teal Blvd. #C
X * Beaverton, OR 97005
X * kirkenda at cs.pdx.edu
X */
X
X
X#include "config.h"
X#include <ctype.h>
X#include "vi.h"
X
X
X
X/* This array describes what each key does */
X#define NO_FUNC (MARK (*)())0
X#define NO_ARGS 0
X#define CURSOR_COUNT 1
X#define CURSOR 2
X#define CURSOR_CNT_KEY 3
X#define CURSOR_MOVED 4
X#define CURSOR_EOL 5
X#define ZERO 6
X#define DIGIT 7
X#define CURSOR_TEXT 8
X#define CURSOR_CNT_CMD 9
X#define KEYWORD 10
X#define NO_FLAGS 0x00
X#define MVMT 0x01 /* this is a movement command */
X#define PTMV 0x02 /* this can be *part* of a movement command */
X#define FRNT 0x04 /* after move, go to front of line */
X#define INCL 0x08 /* include last char when used with c/d/y */
X#define LNMD 0x10 /* use line mode of c/d/y */
X#define NCOL 0x20 /* this command can't change the column# */
X#define NREL 0x40 /* this is "non-relative" -- set the '' mark */
X#define SDOT 0x80 /* set the "dot" variables, for the "." cmd */
Xstatic struct keystru
X{
X MARK (*func)(); /* the function to run */
X uchar args; /* description of the args needed */
X uchar flags; /* other stuff */
X}
X vikeys[] =
X{
X/* NUL not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X/* ^A not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X/* ^B page backward */ {m_scroll, CURSOR_CNT_CMD, FRNT},
X/* ^C not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X/* ^D scroll dn 1/2page*/ {m_scroll, CURSOR_CNT_CMD, NCOL},
X/* ^E scroll up */ {m_scroll, CURSOR_CNT_CMD, NCOL},
X/* ^F page forward */ {m_scroll, CURSOR_CNT_CMD, FRNT},
X/* ^G show file status */ {v_status, NO_ARGS, NO_FLAGS},
X/* ^H move left, like h*/ {m_left, CURSOR_COUNT, MVMT},
X/* ^I not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X/* ^J move down */ {m_updnto, CURSOR_CNT_CMD, MVMT|LNMD},
X/* ^K not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X/* ^L redraw screen */ {v_redraw, NO_ARGS, NO_FLAGS},
X/* ^M mv front next ln */ {m_updnto, CURSOR_CNT_CMD, MVMT|FRNT|LNMD},
X/* ^N move down */ {m_updnto, CURSOR_CNT_CMD, MVMT|LNMD},
X/* ^O not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X/* ^P move up */ {m_updnto, CURSOR_CNT_CMD, MVMT|LNMD},
X/* ^Q not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X/* ^R redraw screen */ {v_redraw, NO_ARGS, NO_FLAGS},
X/* ^S not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X/* ^T not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X/* ^U scroll up 1/2page*/ {m_scroll, CURSOR_CNT_CMD, NCOL},
X/* ^V not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X/* ^W not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X/* ^X not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X/* ^Y scroll down */ {m_scroll, CURSOR_CNT_CMD, NCOL},
X/* ^Z not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X/* ESC not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X/* ^\ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X/* ^] keyword is tag */ {v_tag, KEYWORD, NO_FLAGS},
X/* ^^ previous file */ {v_switch, CURSOR, NO_FLAGS},
X/* ^_ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X/* SPC move right,like l*/ {m_right, CURSOR_COUNT, MVMT},
X/* ! run thru filter */ {v_filter, CURSOR_MOVED, FRNT|LNMD|INCL},
X/* " select cut buffer*/ {v_selcut, CURSOR_CNT_KEY, PTMV},
X#ifndef NO_EXTENSIONS
X/* # increment number */ {v_increment, KEYWORD, SDOT},
X#else
X/* # not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X#endif
X/* $ move to rear */ {m_rear, CURSOR, MVMT|INCL},
X/* % move to match */ {m_match, CURSOR, MVMT|INCL},
X/* & repeat subst */ {v_again, CURSOR_MOVED, SDOT|NCOL|LNMD|INCL},
X/* ' move to a mark */ {m_tomark, CURSOR_CNT_KEY, MVMT|FRNT|NREL|LNMD|INCL},
X#ifndef NO_SENTENCE
X/* ( mv back sentence */ {m_bsentence, CURSOR_COUNT, MVMT},
X/* ) mv fwd sentence */ {m_fsentence, CURSOR_COUNT, MVMT},
X#else
X/* ( not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X/* ) not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X#endif
X#ifndef NO_ERRLIST
X/* * errlist */ {v_errlist, CURSOR, FRNT|NREL},
X#else
X/* * not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X#endif
X/* + mv front next ln */ {m_updnto, CURSOR_CNT_CMD, MVMT|FRNT|LNMD},
X#ifndef NO_CHARSEARCH
X/* , reverse [fFtT] cmd*/ {m__ch, CURSOR_CNT_CMD, MVMT|INCL},
X#else
X/* , not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X#endif
X/* - mv front prev ln */ {m_updnto, CURSOR_CNT_CMD, MVMT|FRNT|LNMD},
X/* . special... */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X/* / forward search */ {m_fsrch, CURSOR_TEXT, MVMT|NREL},
X/* 0 part of count? */ {NO_FUNC, ZERO, MVMT|PTMV},
X/* 1 part of count */ {NO_FUNC, DIGIT, PTMV},
X/* 2 part of count */ {NO_FUNC, DIGIT, PTMV},
X/* 3 part of count */ {NO_FUNC, DIGIT, PTMV},
X/* 4 part of count */ {NO_FUNC, DIGIT, PTMV},
X/* 5 part of count */ {NO_FUNC, DIGIT, PTMV},
X/* 6 part of count */ {NO_FUNC, DIGIT, PTMV},
X/* 7 part of count */ {NO_FUNC, DIGIT, PTMV},
X/* 8 part of count */ {NO_FUNC, DIGIT, PTMV},
X/* 9 part of count */ {NO_FUNC, DIGIT, PTMV},
X/* : run single EX cmd*/ {v_1ex, CURSOR_TEXT, NO_FLAGS},
X#ifndef NO_CHARSEARCH
X/* ; repeat [fFtT] cmd*/ {m__ch, CURSOR_CNT_CMD, MVMT|INCL},
X#else
X/* ; not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X#endif
X/* < shift text left */ {v_lshift, CURSOR_MOVED, SDOT|FRNT|LNMD|INCL},
X/* = not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X/* > shift text right */ {v_rshift, CURSOR_MOVED, SDOT|FRNT|LNMD|INCL},
X/* ? backward search */ {m_bsrch, CURSOR_TEXT, MVMT|NREL},
X#ifndef NO_AT
X/* @ execute a cutbuf */ {v_at, CURSOR_CNT_KEY, NO_FLAGS},
X#else
X/* @ undefined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X#endif
X/* A append at EOL */ {v_insert, CURSOR_CNT_CMD, SDOT},
X/* B move back Word */ {m_bword, CURSOR_CNT_CMD, MVMT},
X/* C change to EOL */ {v_change, CURSOR_EOL, SDOT},
X/* D delete to EOL */ {v_delete, CURSOR_EOL, SDOT},
X/* E move end of Word */ {m_eword, CURSOR_CNT_CMD, MVMT|INCL},
X#ifndef NO_CHARSEARCH
X/* F move bk to char */ {m_Fch, CURSOR_CNT_KEY, MVMT|INCL},
X#else
X/* F not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X#endif
X/* G move to line # */ {m_updnto, CURSOR_CNT_CMD, MVMT|NREL|LNMD|FRNT|INCL},
X/* H move to row */ {m_row, CURSOR_CNT_CMD, MVMT|FRNT},
X/* I insert at front */ {v_insert, CURSOR_CNT_CMD, SDOT},
X/* J join lines */ {v_join, CURSOR_COUNT, SDOT},
X#ifndef NO_EXTENSIONS
X/* K look up keyword */ {v_keyword, KEYWORD, NO_FLAGS},
X#else
X/* K not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X#endif
X/* L move to last row */ {m_row, CURSOR_CNT_CMD, MVMT|FRNT},
X/* M move to mid row */ {m_row, CURSOR_CNT_CMD, MVMT|FRNT},
X/* N reverse prev srch*/ {m_Nsrch, CURSOR, MVMT},
X/* O insert above line*/ {v_insert, CURSOR_CNT_CMD, SDOT},
X/* P paste before */ {v_paste, CURSOR_CNT_CMD, NO_FLAGS},
X/* Q quit to EX mode */ {v_quit, NO_ARGS, NO_FLAGS},
X/* R overtype */ {v_overtype, CURSOR, SDOT},
X/* S change line */ {v_change, CURSOR_MOVED, SDOT},
X#ifndef NO_CHARSEARCH
X/* T move bk to char */ {m_Tch, CURSOR_CNT_KEY, MVMT|INCL},
X#else
X/* T not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X#endif
X/* U undo whole line */ {v_undoline, CURSOR, FRNT},
X/* V not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X/* W move forward Word*/ {m_fword, CURSOR_CNT_CMD, MVMT},
X/* X delete to left */ {v_xchar, CURSOR_CNT_CMD, SDOT},
X/* Y yank text */ {v_yank, CURSOR_MOVED, NCOL},
X/* Z save file & exit */ {v_xit, CURSOR_CNT_KEY, NO_FLAGS},
X/* [ move back section*/ {m_bsection, CURSOR_CNT_KEY, MVMT|LNMD|NREL},
X/* \ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X/* ] move fwd section */ {m_fsection, CURSOR_CNT_KEY, MVMT|LNMD|NREL},
X/* ^ move to front */ {m_front, CURSOR, MVMT},
X/* _ not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X/* ` move to mark */ {m_tomark, CURSOR_CNT_KEY, MVMT|NREL},
X/* a append at cursor */ {v_insert, CURSOR_CNT_CMD, SDOT},
X/* b move back word */ {m_bword, CURSOR_CNT_CMD, MVMT},
X/* c change text */ {v_change, CURSOR_MOVED, SDOT},
X/* d delete op */ {v_delete, CURSOR_MOVED, SDOT|NCOL},
X/* e move end word */ {m_eword, CURSOR_CNT_CMD, MVMT|INCL},
X#ifndef NO_CHARSEARCH
X/* f move fwd for char*/ {m_fch, CURSOR_CNT_KEY, MVMT|INCL},
X#else
X/* f not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X#endif
X/* g not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X/* h move left */ {m_left, CURSOR_COUNT, MVMT},
X/* i insert at cursor */ {v_insert, CURSOR_CNT_CMD, SDOT},
X/* j move down */ {m_updnto, CURSOR_CNT_CMD, MVMT|NCOL|LNMD},
X/* k move up */ {m_updnto, CURSOR_CNT_CMD, MVMT|NCOL|LNMD},
X/* l move right */ {m_right, CURSOR_COUNT, MVMT},
X/* m define a mark */ {v_mark, CURSOR_CNT_KEY, NO_FLAGS},
X/* n repeat prev srch */ {m_nsrch, CURSOR, MVMT},
X/* o insert below line*/ {v_insert, CURSOR_CNT_CMD, SDOT},
X/* p paste after */ {v_paste, CURSOR_CNT_CMD, NO_FLAGS},
X/* q not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X/* r replace chars */ {v_replace, CURSOR_CNT_KEY, SDOT},
X/* s subst N chars */ {v_subst, CURSOR_COUNT, SDOT},
X#ifndef NO_CHARSEARCH
X/* t move fwd to char */ {m_tch, CURSOR_CNT_KEY, MVMT|INCL},
X#else
X/* t not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X#endif
X/* u undo */ {v_undo, CURSOR, NO_FLAGS},
X/* v not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS},
X/* w move fwd word */ {m_fword, CURSOR_CNT_CMD, MVMT},
X/* x delete character */ {v_xchar, CURSOR_CNT_CMD, SDOT},
X/* y yank text */ {v_yank, CURSOR_MOVED, NCOL},
X/* z adjust scrn row */ {m_z, CURSOR_CNT_KEY, NCOL},
X/* { back paragraph */ {m_bparagraph, CURSOR_COUNT, MVMT|LNMD},
X/* | move to column */ {m_tocol, CURSOR_COUNT, NREL},
X/* } fwd paragraph */ {m_fparagraph, CURSOR_COUNT, MVMT|LNMD},
X/* ~ upper/lowercase */ {v_ulcase, CURSOR_COUNT, SDOT},
X/* DEL not defined */ {NO_FUNC, NO_ARGS, NO_FLAGS}
X};
X
X
X
Xvoid vi()
X{
X REG int key; /* keystroke from user */
X long count; /* numeric argument to some functions */
X REG struct keystru *keyptr;/* pointer to vikeys[] element */
X MARK tcurs; /* temporary cursor */
X int prevkey;/* previous key, if d/c/y/</>/! */
X MARK range; /* start of range for d/c/y/</>/! */
X char text[100];
X int dotkey; /* last "key" of a change */
X int dotpkey;/* last "prevkey" of a change */
X int dotkey2;/* last extra "getkey()" of a change */
X int dotcnt; /* last "count" of a change */
X int firstkey;
X REG int i;
X
X /* tell the redraw() function to start from scratch */
X redraw(MARK_UNSET, FALSE);
X
X#ifdef lint
X /* lint says that "range" might be used before it is set. This
X * can't really happen due to the way "range" and "prevkey" are used,
X * but lint doesn't know that. This line is here ONLY to keep lint
X * happy.
X */
X range = 0L;
X#endif
X
X /* safeguard against '.' with no previous command */
X dotkey = 0;
X
X /* go immediately into insert mode, if ":set inputmode" */
X firstkey = 0;
X#ifndef NO_EXTENSIONS
X if (*o_inputmode)
X {
X firstkey = 'i';
X }
X#endif
X
X /* Repeatedly handle VI commands */
X for (count = 0, prevkey = '\0'; mode == MODE_VI; )
X {
X /* if we've moved off the undoable line, then we can't undo it at all */
X if (markline(cursor) != U_line)
X {
X U_line = 0L;
X }
X
X /* report any changes from the previous command */
X if (rptlines >= *o_report)
X {
X redraw(cursor, FALSE);
X msg("%ld lines %s", rptlines, rptlabel);
X }
X rptlines = 0L;
X
X /* get the next command key. It must be ASCII */
X if (firstkey)
X {
X key = firstkey;
X firstkey = 0;
X }
X else
X {
X do
X {
X key = getkey(WHEN_VICMD);
X } while (key < 0 || key > 127);
X }
X
X /* change cw and cW commands to ce and cE, respectively */
X /* (Why? because the real vi does it that way!) */
X if (prevkey == 'c')
X {
X if (key == 'w')
X key = 'e';
X else if (key == 'W')
X key = 'E';
X
X /* wouldn't work right at the end of a word unless we
X * backspace one character before doing the move. This
X * will fix most cases. !!! but not all.
X */
X if (markidx(cursor) > 0 && (key == 'e' || key == 'E'))
X {
X cursor--;
X }
X }
X
X /* look up the structure describing this command */
X keyptr = &vikeys[key];
X
X /* if we're in the middle of a d/c/y/</>/! command, reject
X * anything but movement or a doubled version like "dd".
X */
X if (prevkey && key != prevkey && !(keyptr->flags & (MVMT|PTMV)))
X {
X beep();
X prevkey = 0;
X count = 0;
X continue;
X }
X
X /* set the "dot" variables, if we're supposed to */
X if ((keyptr->flags & SDOT)
X || (prevkey && vikeys[prevkey].flags & SDOT))
X {
X dotkey = key;
X dotpkey = prevkey;
X dotkey2 = '\0';
X dotcnt = count;
X
X /* remember the line before any changes are made */
X if (U_line != markline(cursor))
X {
X U_line = markline(cursor);
X strcpy(U_text, fetchline(U_line));
X }
X }
X
X /* if this is "." then set other vars from the "dot" vars */
X if (key == '.')
X {
X key = dotkey;
X keyptr = &vikeys[key];
X prevkey = dotpkey;
X if (prevkey)
X {
X range = cursor;
X }
X if (count == 0)
X {
X count = dotcnt;
X }
X doingdot = TRUE;
X
X /* remember the line before any changes are made */
X if (U_line != markline(cursor))
X {
X U_line = markline(cursor);
X strcpy(U_text, fetchline(U_line));
X }
X }
X else
X {
X doingdot = FALSE;
X }
X
X /* process the key as a command */
X tcurs = cursor;
X switch (keyptr->args)
X {
X case ZERO:
X if (count == 0)
X {
X tcurs = cursor & ~(BLKSIZE - 1);
X break;
X }
X /* else fall through & treat like other digits... */
X
X case DIGIT:
X count = count * 10 + key - '0';
X break;
X
X case KEYWORD:
X /* if not on a keyword, fail */
X pfetch(markline(cursor));
X key = markidx(cursor);
X if (isascii(ptext[key])
X && !isalnum(ptext[key]) && ptext[key] != '_')
X {
X tcurs = MARK_UNSET;
X break;
X }
X
X /* find the start of the keyword */
X while (key > 0 && (!isascii(ptext[key-1]) ||
X isalnum(ptext[key - 1]) || ptext[key - 1] == '_'))
X {
X key--;
X }
X tcurs = (cursor & ~(BLKSIZE - 1)) + key;
X
X /* copy it into a buffer, and NUL-terminate it */
X i = 0;
X do
X {
X text[i++] = ptext[key++];
X } while (!isascii(ptext[key]) || isalnum(ptext[key]) || ptext[key] == '_');
X text[i] = '\0';
X
X /* call the function */
X tcurs = (*keyptr->func)(text, tcurs, count);
X count = 0L;
X break;
X
X case NO_ARGS:
X if (keyptr->func)
X {
X (*keyptr->func)();
X }
X else
X {
X beep();
X }
X count = 0L;
X break;
X
X case CURSOR_COUNT:
X tcurs = (*keyptr->func)(cursor, count);
X count = 0L;
X break;
X
X case CURSOR:
X tcurs = (*keyptr->func)(cursor);
X count = 0L;
X break;
X
X case CURSOR_CNT_KEY:
X if (doingdot)
X {
X tcurs = (*keyptr->func)(cursor, count, dotkey2);
X }
X else
X {
X /* get a key */
X i = getkey(0);
X if (i == '\033') /* ESC */
X {
X count = 0;
X tcurs = MARK_UNSET;
X break; /* exit from "case CURSOR_CNT_KEY" */
X }
X else if (i == ('V' & 0x1f))
X {
X i = getkey(0);
X }
X
X /* if part of an SDOT command, remember it */
X if (keyptr->flags & SDOT
X || (prevkey && vikeys[prevkey].flags & SDOT))
X {
X dotkey2 = i;
X }
X
X /* do it */
X tcurs = (*keyptr->func)(cursor, count, i);
X }
X count = 0L;
X break;
X
X case CURSOR_MOVED:
X /* '&' and uppercase keys always act like doubled */
X if (key == '&' || isascii(key) && isupper(key))
X {
X prevkey = key;
X }
X
X if (prevkey)
X {
X /* doubling up a command */
X if (!count) count = 1L;
X range = cursor;
X tcurs = range + MARK_AT_LINE(count - 1L);
X count = 0L;
X }
X else
X {
X prevkey = key;
X range = cursor;
X key = -1; /* so we don't think we doubled yet */
X }
X break;
X
X case CURSOR_EOL:
X prevkey = key;
X /* a zero-length line needs special treatment */
X pfetch(markline(cursor));
X if (plen == 0)
X {
X /* act on a zero-length section of text */
X range = tcurs = cursor;
X key = ' ';
X }
X else
X {
X /* act like CURSOR_MOVED with '$' movement */
X range = cursor;
X tcurs = m_rear(cursor, 1L);
X key = '$';
X }
X count = 0L;
X keyptr = &vikeys[key];
X break;
X
X case CURSOR_TEXT:
X do
X {
X text[0] = key;
X if (vgets(key, text + 1, sizeof text - 1) >= 0)
X {
X /* reassure user that <CR> was hit */
X qaddch('\r');
X refresh();
X
X /* call the function with the text */
X tcurs = (*keyptr->func)(cursor, text);
X }
X else
X {
X if (exwrote || mode == MODE_COLON)
X {
X redraw(MARK_UNSET, FALSE);
X }
X mode = MODE_VI;
X }
X } while (mode == MODE_COLON);
X count = 0L;
X break;
X
X case CURSOR_CNT_CMD:
X tcurs = (*keyptr->func)(cursor, count, key);
X count = 0L;
X break;
X }
X
X /* if that command took us out of vi mode, then exit the loop
X * NOW, without tweaking the cursor or anything. This is very
X * important when mode == MODE_QUIT.
X */
X if (mode != MODE_VI)
X {
X break;
X }
X
X /* now move the cursor, as appropriate */
X if (keyptr->args == CURSOR_MOVED)
X {
X /* the < and > keys have FRNT,
X * but it shouldn't be applied yet
X */
X tcurs = adjmove(cursor, tcurs, 0);
X }
X else
X {
X tcurs = adjmove(cursor, tcurs, (int)keyptr->flags);
X }
X
X /* was that the end of a d/c/y/</>/! command? */
X if (prevkey && (prevkey == key || (keyptr->flags & MVMT)) && count == 0L)
X {
X /* if the movement command failed, cancel operation */
X if (tcurs == MARK_UNSET)
X {
X prevkey = 0;
X count = 0;
X continue;
X }
X
X /* make sure range=front and tcurs=rear. Either way,
X * leave cursor=range since that's where we started.
X */
X cursor = range;
X if (tcurs < range)
X {
X range = tcurs;
X tcurs = cursor;
X }
X
X
X /* adjust for line mode & inclusion of last char/line */
X i = (keyptr->flags | vikeys[prevkey].flags);
X if (key == prevkey)
X {
X i |= (INCL|LNMD);
X }
X switch (i & (INCL|LNMD))
X {
X case INCL:
X tcurs++;
X break;
X
X case INCL|LNMD:
X tcurs += BLKSIZE;
X /* fall through... */
X
X case LNMD:
X range &= ~(BLKSIZE - 1);
X tcurs &= ~(BLKSIZE - 1);
X break;
X }
X
X /* run the function */
X tcurs = (*vikeys[prevkey].func)(range, tcurs);
X (void)adjmove(cursor, cursor, 0);
X cursor = adjmove(cursor, tcurs, (int)vikeys[prevkey].flags);
X
X /* cleanup */
X prevkey = 0;
X }
X else if (!prevkey)
X {
X cursor = tcurs;
X }
X }
X}
X
X/* This function adjusts the MARK value that they return; here we make sure
X * it isn't past the end of the line, and that the column hasn't been
X * *accidentally* changed.
X */
XMARK adjmove(old, new, flags)
X MARK old; /* the cursor position before the command */
X REG MARK new; /* the cursor position after the command */
X int flags; /* various flags regarding cursor mvmt */
X{
X static int colno; /* the column number that we want */
X REG char *text; /* used to scan through the line's text */
X REG int i;
X
X#ifdef DEBUG
X watch();
X#endif
X
X /* if the command failed, bag it! */
X if (new == MARK_UNSET)
X {
X beep();
X return old;
X }
X
X /* if this is a non-relative movement, set the '' mark */
X if (flags & NREL)
X {
X mark[26] = old;
X }
X
X /* make sure it isn't past the end of the file */
X if (markline(new) < 1)
X {
X new = MARK_FIRST;
X }
X else if (markline(new) > nlines)
X {
X new = MARK_LAST;
X }
X
X /* fetch the new line */
X pfetch(markline(new));
X
X /* move to the front, if we're supposed to */
X if (flags & FRNT)
X {
X new = m_front(new, 1L);
X }
X
X /* change the column#, or change the mark to suit the column# */
X if (!(flags & NCOL))
X {
X /* change the column# */
X i = markidx(new);
X if (i == BLKSIZE - 1)
X {
X new &= ~(BLKSIZE - 1);
X if (plen > 0)
X {
X new += plen - 1;
X }
X colno = BLKSIZE * 8; /* one heck of a big colno */
X }
X else if (plen > 0)
X {
X if (i >= plen)
X {
X new = (new & ~(BLKSIZE - 1)) + plen - 1;
X }
X colno = idx2col(new, ptext, FALSE);
X }
X else
X {
X new &= ~(BLKSIZE - 1);
X colno = 0;
X }
X }
X else
X {
X /* adjust the mark to get as close as possible to column# */
X for (i = 0, text = ptext; i <= colno && *text; text++)
X {
X if (*text == '\t' && !*o_list)
X {
X i += *o_tabstop - (i % *o_tabstop);
X }
X else if (UCHAR(*text) < ' ' || *text == 127)
X {
X i += 2;
X }
X#ifndef NO_CHARATTR
X else if (*o_charattr && text[0] == '\\' && text[1] == 'f' && text[2])
X {
X text += 2; /* plus one more in "for()" stmt */
X }
X#endif
X else
X {
X i++;
X }
X }
X if (text > ptext)
X {
X text--;
X }
X new = (new & ~(BLKSIZE - 1)) + (int)(text - ptext);
X }
X
X return new;
X}
X
X
X#ifdef DEBUG
Xwatch()
X{
X static wasset;
X
X if (*origname)
X {
X wasset = TRUE;
X }
X else if (wasset)
X {
X msg("origname was clobbered");
X endwin();
X abort();
X }
X
X if (nlines == 0)
X {
X msg("nlines=0");
X endwin();
X abort();
X }
X}
X#endif
eof
if test `wc -c <vi.c` -ne 20322
then
echo vi.c damaged!
fi
fi
if test -f vi.h -a "$1" != -f
then
echo Will not overwrite vi.h
else
echo Extracting vi.h
sed 's/^X//' >vi.h <<\eof
X/* vi.h */
X
X/* Author:
X * Steve Kirkendall
X * 14407 SW Teal Blvd. #C
X * Beaverton, OR 97005
X * kirkenda at cs.pdx.edu
X */
X
X
X/* This is the header file for my version of vi. */
X
X#define VERSION "ELVIS 1.4, by Steve Kirkendall"
X#define COPYING "This version of ELVIS is freely redistributable."
X
X#include <errno.h>
Xextern int errno;
X#if TOS
X#define ENOENT (-AEFILNF)
X#endif
X
X#if TOS
X# include <types.h>
X# define O_RDONLY 0
X# define O_WRONLY 1
X# define O_RDWR 2
X#else
X# if OSK
X# include <modes.h>
X# define O_RDONLY S_IREAD
X# define O_WRONLY S_IWRITE
X# define O_RDWR (S_IREAD | S_IWRITE)
X# define ENOENT E_PNNF
X# else
X# include <sys/types.h>
X# if COHERENT
X# include <sys/fcntl.h>
X# else
X# include <fcntl.h>
X# endif
X# endif
X#endif
X
X#ifndef O_BINARY
X# define O_BINARY 0
X#endif
X
X#include "curses.h"
X
X/*------------------------------------------------------------------------*/
X/* Miscellaneous constants. */
X
X#define INFINITY 2000000001L /* a very large integer */
X#define LONGKEY 10 /* longest possible raw :map key */
X#ifndef MAXRCLEN
X# define MAXRCLEN 1000 /* longest possible .exrc file */
X#endif
X
X/*------------------------------------------------------------------------*/
X/* These describe how temporary files are divided into blocks */
X
X#define BLKSIZE 1024 /* size of blocks */
X#define MAXBLKS (BLKSIZE / sizeof(unsigned short))
Xtypedef union
X{
X char c[BLKSIZE]; /* for text blocks */
X unsigned short n[MAXBLKS]; /* for the header block */
X}
X BLK;
X
X/*------------------------------------------------------------------------*/
X/* These are used manipulate BLK buffers. */
X
Xextern BLK hdr; /* buffer for the header block */
Xextern BLK *blkget(); /* given index into hdr.c[], reads block */
Xextern BLK *blkadd(); /* inserts a new block into hdr.c[] */
X
X/*------------------------------------------------------------------------*/
X/* These are used to keep track of various flags */
Xextern struct _viflags
X{
X short file; /* file flags */
X}
X viflags;
X
X/* file flags */
X#define NEWFILE 0x0001 /* the file was just created */
X#define READONLY 0x0002 /* the file is read-only */
X#define HADNUL 0x0004 /* the file contained NUL characters */
X#define MODIFIED 0x0008 /* the file has been modified */
X#define NOFILE 0x0010 /* no name is known for the current text */
X#define ADDEDNL 0x0020 /* newlines were added to the file */
X
X/* macros used to set/clear/test flags */
X#define setflag(x,y) viflags.x |= y
X#define clrflag(x,y) viflags.x &= ~y
X#define tstflag(x,y) (viflags.x & y)
X#define initflags() viflags.file = 0;
X
X/* The options */
Xextern char o_autoindent[1];
Xextern char o_autoprint[1];
Xextern char o_autowrite[1];
X#ifndef NO_ERRLIST
Xextern char o_cc[30];
X#endif
X#ifndef NO_CHARATTR
Xextern char o_charattr[1];
X#endif
Xextern char o_columns[3];
Xextern char o_digraph[1];
Xextern char o_directory[30];
Xextern char o_edcompatible[1];
Xextern char o_errorbells[1];
Xextern char o_exrefresh[1];
X#ifndef NO_DIGRAPH
Xextern char o_flipcase[80];
X#endif
X#ifndef NO_SENTENCE
Xextern char o_hideformat[1];
X#endif
Xextern char o_ignorecase[1];
X#ifndef NO_EXTENSIONS
Xextern char o_inputmode[1];
X#endif
Xextern char o_keytime[3];
Xextern char o_keywordprg[80];
Xextern char o_lines[3];
Xextern char o_list[1];
X#ifndef NO_MAGIC
Xextern char o_magic[1];
X#endif
X#ifndef NO_ERRLIST
Xextern char o_make[30];
X#endif
X#ifndef NO_MODELINE
Xextern char o_modeline[1];
X#endif
X#ifndef NO_SENTENCE
Xextern char o_paragraphs[30];
X#endif
X#if MSDOS
Xextern char o_pcbios[1];
X#endif
Xextern char o_readonly[1];
Xextern char o_report[3];
Xextern char o_scroll[3];
X#ifndef NO_SENTENCE
Xextern char o_sections[30];
X#endif
Xextern char o_shell[60];
X#ifndef NO_SHOWMATCH
Xextern char o_showmatch[1];
X#endif
X#ifndef NO_SHOWMODE
Xextern char o_smd[1];
X#endif
Xextern char o_shiftwidth[3];
Xextern char o_sidescroll[3];
Xextern char o_sync[1];
Xextern char o_tabstop[3];
Xextern char o_term[30];
Xextern char o_vbell[1];
Xextern char o_warn[1];
Xextern char o_wrapmargin[3];
Xextern char o_wrapscan[1];
X
X/*------------------------------------------------------------------------*/
X/* These help support the single-line multi-change "undo" -- shift-U */
X
Xextern char U_text[BLKSIZE];
Xextern long U_line;
X
X/*------------------------------------------------------------------------*/
X/* These are used to refer to places in the text */
X
Xtypedef long MARK;
X#define markline(x) (long)((x) / BLKSIZE)
X#define markidx(x) (int)((x) & (BLKSIZE - 1))
X#define MARK_UNSET ((MARK)0)
X#define MARK_FIRST ((MARK)BLKSIZE)
X#define MARK_LAST ((MARK)(nlines * BLKSIZE))
X#define MARK_AT_LINE(x) ((MARK)((x) * BLKSIZE))
X
X#define NMARKS 29
Xextern MARK mark[NMARKS]; /* marks a-z, plus mark ' and two temps */
Xextern MARK cursor; /* mark where line is */
X
X/*------------------------------------------------------------------------*/
X/* These are used to keep track of the current & previous files. */
X
Xextern long origtime; /* modification date&time of the current file */
Xextern char origname[256]; /* name of the current file */
Xextern char prevorig[256]; /* name of the preceding file */
Xextern long prevline; /* line number from preceding file */
X
X/*------------------------------------------------------------------------*/
X/* misc housekeeping variables & functions */
X
Xextern int tmpfd; /* fd used to access the tmp file */
Xextern long lnum[MAXBLKS]; /* last line# of each block */
Xextern long nlines; /* number of lines in the file */
Xextern char args[BLKSIZE]; /* file names given on the command line */
Xextern int argno; /* the current element of args[] */
Xextern int nargs; /* number of filenames in args */
Xextern long changes; /* counts changes, to prohibit short-cuts */
Xextern int significant; /* boolean: was a *REAL* change made? */
Xextern int mustredraw; /* boolean: force total redraw of screen? */
Xextern BLK tmpblk; /* a block used to accumulate changes */
Xextern long topline; /* file line number of top line */
Xextern int leftcol; /* column number of left col */
X#define botline (topline + LINES - 2)
X#define rightcol (leftcol + COLS - 1)
Xextern int physcol; /* physical column number that cursor is on */
Xextern int physrow; /* physical row number that cursor is on */
Xextern int exwrote; /* used to detect verbose ex commands */
Xextern int doingdot; /* boolean: are we doing the "." command? */
Xextern int doingglobal; /* boolean: are doing a ":g" command? */
Xextern long rptlines; /* number of lines affected by a command */
Xextern char *rptlabel; /* description of how lines were affected */
Xextern char *fetchline(); /* read a given line from tmp file */
Xextern char *parseptrn(); /* isolate a regexp in a line */
Xextern MARK paste(); /* paste from cut buffer to a given point */
Xextern char *wildcard(); /* expand wildcards in filenames */
Xextern MARK input(); /* inserts characters from keyboard */
Xextern char *linespec(); /* finds the end of a /regexp/ string */
X#define ctrl(ch) ((ch)&037)
X#ifndef NO_RECYCLE
Xextern long allocate(); /* allocate a free block of the tmp file */
X#endif
Xextern int trapint(); /* trap handler for SIGINT */
Xextern void blkdirty(); /* marks a block as being "dirty" */
Xextern void blkflush(); /* writes a single dirty block to the disk */
Xextern void blksync(); /* forces all "dirty" blocks to disk */
Xextern void blkinit(); /* resets the block cache to "empty" state */
Xextern void beep(); /* rings the terminal's bell */
Xextern void exrefresh(); /* writes text to the screen */
Xextern void msg(); /* writes a printf-style message to the screen */
Xextern void reset_msg(); /* resets the "manymsgs" flag */
Xextern void endmsgs(); /* if "manymsgs" is set, then scroll up 1 line */
Xextern void garbage(); /* reclaims any garbage blocks */
Xextern void redraw(); /* updates the screen after a change */
Xextern void resume_curses();/* puts the terminal in "cbreak" mode */
Xextern void beforedo(); /* saves current revision before a new change */
Xextern void afterdo(); /* marks end of a beforedo() change */
Xextern void abortdo(); /* like "afterdo()" followed by "undo()" */
Xextern int undo(); /* restores file to previous undo() */
Xextern void dumpkey(); /* lists key mappings to the screen */
Xextern void mapkey(); /* defines a new key mapping */
Xextern void savekeys(); /* lists key mappings to a file */
Xextern void redrawrange(); /* records clues from modify.c */
Xextern void cut(); /* saves text in a cut buffer */
Xextern void delete(); /* deletes text */
Xextern void add(); /* adds text */
Xextern void change(); /* deletes text, and then adds other text */
Xextern void cutswitch(); /* updates cut buffers when we switch files */
Xextern void do_abbr(); /* defines or lists abbreviations */
Xextern void do_digraph(); /* defines or lists digraphs */
Xextern void exstring(); /* execute a string as EX commands */
Xextern void dumpopts();
Xextern void setopts();
Xextern void saveopts();
X#ifndef NO_DIGRAPH
Xextern void savedigs();
X#endif
X#ifndef NO_ABBR
Xextern void saveabbr();
X#endif
Xextern void cutname();
Xextern void cutname();
Xextern void initopts();
Xextern void cutend();
X
X/*------------------------------------------------------------------------*/
X/* macros that are used as control structures */
X
X#define BeforeAfter(before, after) for((before),bavar=1;bavar;(after),bavar=0)
X#define ChangeText BeforeAfter(beforedo(FALSE),afterdo())
X
Xextern int bavar; /* used only in BeforeAfter macros */
X
X/*------------------------------------------------------------------------*/
X/* These are the movement commands. Each accepts a mark for the starting */
X/* location & number and returns a mark for the destination. */
X
Xextern MARK m_updnto(); /* k j G */
Xextern MARK m_right(); /* h */
Xextern MARK m_left(); /* l */
Xextern MARK m_tocol(); /* | */
Xextern MARK m_front(); /* ^ */
Xextern MARK m_rear(); /* $ */
Xextern MARK m_fword(); /* w */
Xextern MARK m_bword(); /* b */
Xextern MARK m_eword(); /* e */
Xextern MARK m_fWord(); /* W */
Xextern MARK m_bWord(); /* B */
Xextern MARK m_eWord(); /* E */
Xextern MARK m_fparagraph(); /* } */
Xextern MARK m_bparagraph(); /* { */
Xextern MARK m_fsection(); /* ]] */
Xextern MARK m_bsection(); /* [[ */
Xextern MARK m_match(); /* % */
X#ifndef NO_SENTENCE
X extern MARK m_fsentence(); /* ) */
X extern MARK m_bsentence(); /* ( */
X#endif
Xextern MARK m_tomark(); /* 'm */
Xextern MARK m_nsrch(); /* n */
Xextern MARK m_Nsrch(); /* N */
Xextern MARK m_fsrch(); /* /regexp */
Xextern MARK m_bsrch(); /* ?regexp */
X#ifndef NO_CHARSEARCH
X extern MARK m__ch(); /* ; , */
X extern MARK m_fch(); /* f */
X extern MARK m_tch(); /* t */
X extern MARK m_Fch(); /* F */
X extern MARK m_Tch(); /* T */
X#endif
Xextern MARK m_row(); /* H L M */
Xextern MARK m_z(); /* z */
Xextern MARK m_scroll(); /* ^B ^F ^E ^Y ^U ^D */
X
X/* Some stuff that is used by movement functions... */
X
Xextern MARK adjmove(); /* a helper fn, used by move fns */
X
X/* This macro is used to set the default value of cnt */
X#define DEFAULT(val) if (cnt < 1) cnt = (val)
X
X/* These are used to minimize calls to fetchline() */
Xextern int plen; /* length of the line */
Xextern long pline; /* line number that len refers to */
Xextern long pchgs; /* "changes" level that len refers to */
Xextern char *ptext; /* text of previous line, if valid */
Xextern void pfetch();
Xextern char digraph();
X
X/* This is used to build a MARK that corresponds to a specific point in the
X * line that was most recently pfetch'ed.
X */
X#define buildmark(text) (MARK)(BLKSIZE * pline + (int)((text) - ptext))
X
X
X/*------------------------------------------------------------------------*/
X/* These are used to handle EX commands. */
X
X#define CMD_NULL 0 /* NOT A VALID COMMAND */
X#define CMD_ABBR 1 /* "define an abbreviation" */
X#define CMD_ARGS 2 /* "show me the args" */
X#define CMD_APPEND 3 /* "insert lines after this line" */
X#define CMD_AT 4 /* "execute a cut buffer's contents via EX" */
X#define CMD_BANG 5 /* "run a single shell command" */
X#define CMD_CC 6 /* "run `cc` and then do CMD_ERRLIST" */
X#define CMD_CD 7 /* "change directories" */
X#define CMD_CHANGE 8 /* "change some lines" */
X#define CMD_COPY 9 /* "copy the selected text to a given place" */
X#define CMD_DELETE 10 /* "delete the selected text" */
X#define CMD_DIGRAPH 11 /* "add a digraph, or display them all" */
X#define CMD_EDIT 12 /* "switch to a different file" */
X#define CMD_EQUAL 13 /* "display a line number" */
X#define CMD_ERRLIST 14 /* "locate the next error in a list" */
X#define CMD_FILE 15 /* "show the file's status" */
X#define CMD_GLOBAL 16 /* "globally search & do a command" */
X#define CMD_INSERT 17 /* "insert lines before the current line" */
X#define CMD_JOIN 18 /* "join the selected line & the one after" */
X#define CMD_LIST 19 /* "print lines, making control chars visible" */
X#define CMD_MAKE 20 /* "run `make` and then do CMD_ERRLIST" */
X#define CMD_MAP 21 /* "adjust the keyboard map" */
X#define CMD_MARK 22 /* "mark this line" */
X#define CMD_MKEXRC 23 /* "make a .exrc file" */
X#define CMD_MOVE 24 /* "move the selected text to a given place" */
X#define CMD_NEXT 25 /* "switch to next file in args" */
X#define CMD_NUMBER 26 /* "print lines from the file w/ line numbers" */
X#define CMD_PRESERVE 27 /* "act as though vi crashed" */
X#define CMD_PREVIOUS 28 /* "switch to the previous file in args" */
X#define CMD_PRINT 29 /* "print the selected text" */
X#define CMD_PUT 30 /* "insert any cut lines before this line" */
X#define CMD_QUIT 31 /* "quit without writing the file" */
X#define CMD_READ 32 /* "append the given file after this line */
X#define CMD_RECOVER 33 /* "recover file after vi crashes" - USE -r FLAG */
X#define CMD_REWIND 34 /* "rewind to first file" */
X#define CMD_SET 35 /* "set a variable's value" */
X#define CMD_SHELL 36 /* "run some lines through a command" */
X#define CMD_SHIFTL 37 /* "shift lines left" */
X#define CMD_SHIFTR 38 /* "shift lines right" */
X#define CMD_SOURCE 39 /* "interpret a file's contents as ex commands" */
X#define CMD_STOP 40 /* same as CMD_SUSPEND */
X#define CMD_SUBAGAIN 41 /* "repeat the previous substitution" */
X#define CMD_SUBSTITUTE 42 /* "substitute text in this line" */
X#define CMD_SUSPEND 43 /* "suspend the vi session" */
X#define CMD_TR 44 /* "transliterate chars in the selected lines" */
X#define CMD_TAG 45 /* "go to a particular tag" */
X#define CMD_UNABBR 46 /* "remove an abbreviation definition" */
X#define CMD_UNDO 47 /* "undo the previous command" */
X#define CMD_UNMAP 48 /* "remove a key sequence map */
X#define CMD_VERSION 49 /* "describe which version this is" */
X#define CMD_VGLOBAL 50 /* "apply a cmd to lines NOT containing an RE" */
X#define CMD_VISUAL 51 /* "go into visual mode" */
X#define CMD_WQUIT 52 /* "write this file out (any case) & quit" */
X#define CMD_WRITE 53 /* "write the selected(?) text to a given file" */
X#define CMD_XIT 54 /* "write this file out (if modified) & quit" */
X#define CMD_YANK 55 /* "copy the selected text into the cut buffer" */
X#ifdef DEBUG
X# define CMD_DEBUG 56 /* access to internal data structures */
X# define CMD_VALIDATE 57 /* check for internal consistency */
X#endif
Xtypedef int CMD;
X
Xextern void ex();
Xextern void vi();
Xextern void doexcmd();
X
X#ifndef NO_ABBR
Xextern void cmd_abbr();
X#endif
Xextern void cmd_append();
Xextern void cmd_args();
X#ifndef NO_AT
Xextern void cmd_at();
X#endif
Xextern void cmd_cd();
Xextern void cmd_delete();
X#ifndef NO_DIGRAPH
Xextern void cmd_digraph();
X#endif
Xextern void cmd_edit();
X#ifndef NO_ERRLIST
Xextern void cmd_errlist();
X#endif
Xextern void cmd_file();
Xextern void cmd_global();
Xextern void cmd_join();
Xextern void cmd_mark();
X#ifndef NO_ERRLIST
Xextern void cmd_make();
X#endif
Xextern void cmd_map();
X#ifndef NO_MKEXRC
Xextern void cmd_mkexrc();
X#endif
Xextern void cmd_next();
Xextern void cmd_print();
Xextern void cmd_put();
Xextern void cmd_read();
Xextern void cmd_set();
Xextern void cmd_shell();
Xextern void cmd_shift();
Xextern void cmd_source();
Xextern void cmd_substitute();
Xextern void cmd_tag();
Xextern void cmd_undo();
Xextern void cmd_version();
Xextern void cmd_visual();
Xextern void cmd_write();
Xextern void cmd_xit();
Xextern void cmd_move();
X#ifdef DEBUG
Xextern void cmd_debug();
Xextern void cmd_validate();
X#endif
X
X/*----------------------------------------------------------------------*/
X/* These are used to handle VI commands */
X
Xextern MARK v_1ex(); /* : */
Xextern MARK v_mark(); /* m */
Xextern MARK v_quit(); /* Q */
Xextern MARK v_redraw(); /* ^L ^R */
Xextern MARK v_ulcase(); /* ~ */
Xextern MARK v_undo(); /* u */
Xextern MARK v_xchar(); /* x */
Xextern MARK v_Xchar(); /* X */
Xextern MARK v_replace(); /* r */
Xextern MARK v_overtype(); /* R */
Xextern MARK v_selcut(); /* " */
Xextern MARK v_paste(); /* p P */
Xextern MARK v_yank(); /* y Y */
Xextern MARK v_delete(); /* d D */
Xextern MARK v_join(); /* J */
Xextern MARK v_insert(); /* a A i I o O */
Xextern MARK v_change(); /* c C */
Xextern MARK v_subst(); /* s */
Xextern MARK v_lshift(); /* < */
Xextern MARK v_rshift(); /* > */
Xextern MARK v_filter(); /* ! */
Xextern MARK v_status(); /* ^G */
Xextern MARK v_switch(); /* ^^ */
Xextern MARK v_tag(); /* ^] */
Xextern MARK v_xit(); /* ZZ */
Xextern MARK v_undoline(); /* U */
Xextern MARK v_again(); /* & */
X#ifndef NO_EXTENSIONS
X extern MARK v_keyword(); /* ^K */
X extern MARK v_increment(); /* * */
X#endif
X#ifndef NO_ERRLIST
X extern MARK v_errlist(); /* * */
X#endif
X#ifndef NO_AT
X extern MARK v_at(); /* @ */
X#endif
X
X/*----------------------------------------------------------------------*/
X/* These describe what mode we're in */
X
X#define MODE_EX 1 /* executing ex commands */
X#define MODE_VI 2 /* executing vi commands */
X#define MODE_COLON 3 /* executing an ex command from vi mode */
X#define MODE_QUIT 4
Xextern int mode;
X
X#define WHEN_VICMD 1 /* getkey: we're reading a VI command */
X#define WHEN_VIINP 2 /* getkey: we're in VI's INPUT mode */
X#define WHEN_VIREP 4 /* getkey: we're in VI's REPLACE mode */
X#define WHEN_EX 8 /* getkey: we're in EX mode */
X#define WHEN_MSG 16 /* getkey: we're at a "more" prompt */
X#define WHEN_INMV 256 /* in input mode, interpret the key in VICMD mode */
eof
if test `wc -c <vi.h` -ne 18110
then
echo vi.h damaged!
fi
fi
if test -f refont.c -a "$1" != -f
then
echo Will not overwrite refont.c
else
echo Extracting refont.c
sed 's/^X//' >refont.c <<\eof
X/* refont.c */
X
X/* Author:
X * Steve Kirkendall
X * 14407 SW Teal Blvd. #C
X * Beaverton, OR 97005
X * kirkenda at cs.pdx.edu
X */
X
X
X/* This file contains the complete source code for the refont program */
X
X/* The refont program converts font designations to the format of your choice.
X * Known font formats are:
X * -b overtype notation, using backspaces
X * -c overtype notation, using carriage returns
X * -d the "dot" command notation used by nroff (doesn't work well)
X * -e Epson-compatible line printer codes
X * -f the "\f" notation
X * -x none (strip out the font codes)
X *
X * Other flags are:
X * -I recognize \f and dot notations in input
X * -F output a formfeed character between files
X */
X
X#include <stdio.h>
X#include "config.h"
X
X/* the program name, for diagnostics */
Xchar *progname;
X
X/* remembers which output format to use */
Xint outfmt = 'f';
X
X/* do we allow "dot" and "backslash-f" on input? */
Xint infmt = 0;
X
X/* do we insert formfeeds between input files? */
Xint add_form_feed = 0;
X
Xmain(argc, argv)
X int argc; /* number of command-line args */
X char **argv; /* values of the command line args */
X{
X FILE *fp;
X int i, j;
X int retcode;
X
X progname = argv[0];
X
X /* parse the flags */
X i = 1;
X if (i < argc && argv[i][0] == '-' && argv[i][1])
X {
X for (j = 1; argv[i][j]; j++)
X {
X switch (argv[i][j])
X {
X case 'b':
X#if !OSK
X case 'c':
X#endif
X case 'd':
X case 'e':
X case 'f':
X case 'x':
X outfmt = argv[i][j];
X break;
X
X case 'I':
X infmt = 'I';
X break;
X
X case 'F':
X add_form_feed = 1;
X break;
X
X default:
X usage();
X }
X }
X i++;
X }
X
X retcode = 0;
X if (i == argc)
X {
X /* probably shouldn't read from keyboard */
X if (isatty(fileno(stdin)))
X {
X usage();
X }
X
X /* no files named, so use stdin */
X refont(stdin);
X }
X else
X {
X for (; i < argc; i++)
X {
X fp = fopen(argv[i], "r");
X if (!fp)
X {
X perror(argv[i]);
X retcode = 1;
X }
X else
X {
X refont(fp);
X if (i < argc - 1 && add_form_feed)
X {
X putchar('\f');
X }
X fclose(fp);
X }
X }
X }
X
X exit(retcode);
X}
X
Xusage()
X{
X fputs("usage: ", stderr);
X fputs(progname, stderr);
X fputs(" [-bcdefxFI] [filename]...\n", stderr);
X exit(2);
X}
X
X/* This function does the refont thing to a single file */
X/* I apologize for the length of this function. It is gross. */
Xrefont(fp)
X FILE *fp;
X{
X char textbuf[1025]; /* chars of a line of text */
X char fontbuf[1025]; /* fonts of chars in fontbuf */
X int col; /* where we are in the line */
X int font; /* remembered font */
X int more; /* more characters to be output? */
X int ch;
X
X /* reset some stuff */
X for (col = sizeof fontbuf; --col >= 0; )
X {
X fontbuf[col] = 'R';
X textbuf[col] = '\0';
X }
X col = 0;
X font = 'R';
X
X /* get the first char - quit if eof */
X while ((ch = getc(fp)) != EOF)
X {
X /* if "dot" command, read the rest of the command */
X if (infmt == 'I' && ch == '.' && col == 0)
X {
X
X textbuf[col++] = '.';
X textbuf[col++] = getc(fp);
X textbuf[col++] = getc(fp);
X textbuf[col++] = ch = getc(fp);
X
X /* is it a font line? */
X font = 0;
X if (textbuf[1] == 'u' && textbuf[2] == 'l')
X {
X font = 'U';
X }
X else if (textbuf[1] == 'b' && textbuf[2] == 'o')
X {
X font = 'B';
X }
X else if (textbuf[1] == 'i' && textbuf[2] == 't')
X {
X font = 'I';
X }
X
X /* if it is, discard the stuff so far but remember font */
X if (font)
X {
X while (col > 0)
X {
X textbuf[--col] = '\0';
X }
X }
X else /* some other format line - write it literally */
X {
X while (ch != '\n')
X {
X textbuf[col++] = ch = getc(fp);
X }
X fputs(textbuf, fp);
X while (col > 0)
X {
X textbuf[--col] = '\0';
X }
X }
X continue;
X }
X
X /* is it a "\f" formatted font? */
X if (infmt == 'I' && ch == '\\')
X {
X ch = getc(fp);
X if (ch == 'f')
X {
X font = getc(fp);
X }
X else
X {
X textbuf[col++] = '\\';
X textbuf[col++] = ch;
X }
X continue;
X }
X
X /* is it an Epson font? */
X if (ch == '\033')
X {
X ch = getc(fp);
X switch (ch)
X {
X case '4':
X font = 'I';
X break;
X
X case 'E':
X case 'G':
X font = 'B';
X break;
X
X case '5':
X case 'F':
X case 'H':
X font = 'R';
X break;
X
X case '-':
X font = (getc(fp) & 1) ? 'U' : 'R';
X break;
X }
X continue;
X }
X
X /* control characters? */
X if (ch == '\b')
X {
X if (col > 0)
X col--;
X continue;
X }
X else if (ch == '\t')
X {
X do
X {
X if (textbuf[col] == '\0')
X {
X textbuf[col] = ' ';
X }
X col++;
X } while (col & 7);
X continue;
X }
X#if !OSK
X else if (ch == '\r')
X {
X col = 0;
X continue;
X }
X#endif
X else if (ch == ' ')
X {
X if (textbuf[col] == '\0')
X {
X textbuf[col] = ' ';
X fontbuf[col] = font;
X col++;
X }
X continue;
X }
X
X /* newline? */
X if (ch == '\n')
X {
X more = 0;
X for (col = 0, font = 'R'; textbuf[col]; col++)
X {
X if (fontbuf[col] != font)
X {
X switch (outfmt)
X {
X case 'd':
X putchar('\n');
X switch (fontbuf[col])
X {
X case 'B':
X fputs(".bo\n", stdout);
X break;
X
X case 'I':
X fputs(".it\n", stdout);
X break;
X
X case 'U':
X fputs(".ul\n", stdout);
X break;
X }
X while (textbuf[col] == ' ')
X {
X col++;
X }
X break;
X
X case 'e':
X switch (fontbuf[col])
X {
X case 'B':
X fputs("\033E", stdout);
X break;
X
X case 'I':
X fputs("\0334", stdout);
X break;
X
X case 'U':
X fputs("\033-1", stdout);
X break;
X
X default:
X switch (font)
X {
X case 'B':
X fputs("\033F", stdout);
X break;
X
X case 'I':
X fputs("\0335", stdout);
X break;
X
X case 'U':
X fputs("\033-0", stdout);
X break;
X }
X }
X break;
X
X case 'f':
X putchar('\\');
X putchar('f');
X putchar(fontbuf[col]);
X break;
X }
X
X font = fontbuf[col];
X }
X
X if (fontbuf[col] != 'R' && textbuf[col] != ' ')
X {
X switch (outfmt)
X {
X case 'b':
X if (fontbuf[col] == 'B')
X {
X putchar(textbuf[col]);
X }
X else
X {
X putchar('_');
X }
X putchar('\b');
X break;
X#if !OSK
X case 'c':
X more = col + 1;
X break;
X#endif
X }
X }
X
X putchar(textbuf[col]);
X }
X
X#if !OSK
X /* another pass? */
X if (more > 0)
X {
X putchar('\r');
X for (col = 0; col < more; col++)
X {
X switch (fontbuf[col])
X {
X case 'I':
X case 'U':
X putchar('_');
X break;
X
X case 'B':
X putchar(textbuf[col]);
X break;
X
X default:
X putchar(' ');
X }
X }
X }
X#endif /* not OSK */
X
X /* newline */
X if (font != 'R')
X {
X switch (outfmt)
X {
X case 'f':
X putchar('\\');
X putchar('f');
X putchar('R');
X break;
X
X case 'e':
X switch (font)
X {
X case 'B':
X fputs("\033F", stdout);
X break;
X
X case 'I':
X fputs("\0335", stdout);
X break;
X
X case 'U':
X fputs("\033-0", stdout);
X break;
X }
X }
X }
X putchar('\n');
X
X /* reset some stuff */
X for (col = sizeof fontbuf; --col >= 0; )
X {
X fontbuf[col] = 'R';
X textbuf[col] = '\0';
X }
X col = 0;
X font = 'R';
X continue;
X }
X
X /* normal character */
X if (font != 'R')
X {
X textbuf[col] = ch;
X fontbuf[col] = font;
X }
X else if (textbuf[col] == '_')
X {
X textbuf[col] = ch;
X fontbuf[col] = 'U';
X }
X else if (textbuf[col] && textbuf[col] != ' ' && ch == '_')
X {
X fontbuf[col] = 'U';
X }
X else if (textbuf[col] == ch)
X {
X fontbuf[col] = 'B';
X }
X else
X {
X textbuf[col] = ch;
X }
X col++;
X }
X}
eof
if test `wc -c <refont.c` -ne 7638
then
echo refont.c damaged!
fi
fi
exit 0
-------------------------------------------------------------------------------
Steve Kirkendall kirkenda at cs.pdx.edu Grad student at Portland State U.
More information about the Alt.sources
mailing list