home *** CD-ROM | disk | FTP | other *** search
- From: kirkenda@eecs.cs.pdx.edu (Steve Kirkendall)
- Newsgroups: alt.sources
- Subject: Elvis 1.4, part 8 of 8
- Message-ID: <832@pdxgate.UUCP>
- Date: 3 Dec 90 21:36:52 GMT
-
-
- # --------------------------- cut here ----------------------------
- # This is a shar archive. To unpack it, save it to a file, and delete
- # anything above the "cut here" line. Then run sh on the file.
- #
- # -rw-r--r-- 1 kirkenda 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@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@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@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@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@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@cs.pdx.edu Grad student at Portland State U.
-