Path: utzoo!utgpu!cs.utexas.edu!uunet!zephyr.ens.tek.com!tektronix!nosun!qiclab!pdxgate!eecs.cs.pdx.edu!kirkenda 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 Sender: news@pdxgate.UUCP Reply-To: kirkenda@eecs.cs.pdx.edu (Steve Kirkendall) Organization: Portland State University, Portland, OR Lines: 2696 # --------------------------- 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 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 X#include X#endif X#if TOS X#include X#include X#endif X#if OSK X# include 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 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 ."); 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 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 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 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.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 Xextern int errno; X#if TOS X#define ENOENT (-AEFILNF) X#endif X X#if TOS X# include X# define O_RDONLY 0 X# define O_WRONLY 1 X# define O_RDWR 2 X#else X# if OSK X# include 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 X# if COHERENT X# include X# else X# include 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 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 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