v08i005: stevie 3.69 - part 3 of 8
Brandon S. Allbery - comp.sources.misc
allbery at uunet.UU.NET
Sun Aug 20 10:47:25 AEST 1989
Posting-number: Volume 8, Issue 5
Submitted-by: tony at cs.utexas.edu@wldrdg.UUCP (Tony Andrews)
Archive-name: stevie3.68/part03
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
# normal.c
# ops.c
# ops.h
# param.c
# param.h
# ptrfunc.c
# This archive created: Sun Aug 13 11:46:00 1989
export PATH; PATH=/bin:$PATH
echo shar: extracting "'normal.c'" '(16909 characters)'
if test -f 'normal.c'
then
echo shar: will not over-write existing file "'normal.c'"
else
sed 's/^X//' << \HE_HATES_THESE_CANS > 'normal.c'
X/* $Header: /nw/tony/src/stevie/src/RCS/normal.c,v 1.25 89/08/06 09:50:25 tony Exp $
X *
X * Contains the main routine for processing characters in command mode.
X * Communicates closely with the code in ops.c to handle the operators.
X */
X
X#include "stevie.h"
X#include "ops.h"
X
X/*
X * Generally speaking, every command in normal() should either clear any
X * pending operator (with CLEAROP), or set the motion type variable.
X */
X
X#define CLEAROP (operator=NOP) /* clear any pending operator */
X
Xint operator = NOP; /* current pending operator */
Xint mtype; /* type of the current cursor motion */
Xbool_t mincl; /* true if char motion is inclusive */
XLPTR startop; /* cursor pos. at start of operator */
X
X/*
X * Operators can have counts either before the operator, or between the
X * operator and the following cursor motion as in:
X *
X * d3w or 3dw
X *
X * If a count is given before the operator, it is saved in opnum. If
X * normal() is called with a pending operator, the count in opnum (if
X * present) overrides any count that came later.
X */
Xstatic int opnum = 0;
X
X#define DEFAULT1(x) (((x) == 0) ? 1 : (x))
X
X/*
X * normal(c)
X *
X * Execute a command in command mode.
X *
X * This is basically a big switch with the cases arranged in rough categories
X * in the following order:
X *
X * 1. File positioning commands
X * 2. Control commands (e.g. ^G, Z, screen redraw, etc)
X * 3. Character motions
X * 4. Search commands (of various kinds)
X * 5. Edit commands (e.g. J, x, X)
X * 6. Insert commands (e.g. i, o, O, A)
X * 7. Operators
X * 8. Abbreviations (e.g. D, C)
X * 9. Marks
X */
Xvoid
Xnormal(c)
Xregister int c;
X{
X register int n;
X register char *s; /* temporary variable for misc. strings */
X bool_t flag = FALSE;
X int type = 0; /* used in some operations to modify type */
X int dir = FORWARD; /* search direction */
X int nchar = NUL;
X bool_t finish_op;
X
X /*
X * If there is an operator pending, then the command we take
X * this time will terminate it. Finish_op tells us to finish
X * the operation before returning this time (unless the operation
X * was cancelled.
X */
X finish_op = (operator != NOP);
X
X /*
X * If we're in the middle of an operator AND we had a count before
X * the operator, then that count overrides the current value of
X * Prenum. What this means effectively, is that commands like
X * "3dw" get turned into "d3w" which makes things fall into place
X * pretty neatly.
X */
X if (finish_op) {
X if (opnum != 0)
X Prenum = opnum;
X } else
X opnum = 0;
X
X u_lcheck(); /* clear the "line undo" buffer if we've moved */
X
X switch (c & 0xff) {
X
X /*
X * Screen positioning commands
X */
X case CTRL('D'):
X CLEAROP;
X if (Prenum)
X P(P_SS) = (Prenum > Rows-1) ? Rows-1 : Prenum;
X scrollup(P(P_SS));
X onedown(P(P_SS));
X updatescreen();
X break;
X
X case CTRL('U'):
X CLEAROP;
X if (Prenum)
X P(P_SS) = (Prenum > Rows-1) ? Rows-1 : Prenum;
X scrolldown(P(P_SS));
X oneup(P(P_SS));
X updatescreen();
X break;
X
X /*
X * This is kind of a hack. If we're moving by one page, the calls
X * to stuffin() do exactly the right thing in terms of leaving
X * some context, and so on. If a count was given, we don't have
X * to worry about these issues.
X */
X case CTRL('F'):
X CLEAROP;
X n = DEFAULT1(Prenum);
X if (n > 1) {
X if ( ! onedown(Rows * n) )
X beep();
X cursupdate();
X } else {
X screenclear();
X stuffin("Lz\nM");
X }
X break;
X
X case CTRL('B'):
X CLEAROP;
X n = DEFAULT1(Prenum);
X if (n > 1) {
X if ( ! oneup(Rows * n) )
X beep();
X cursupdate();
X } else {
X screenclear();
X stuffin("Hz-M");
X }
X break;
X
X case CTRL('E'):
X CLEAROP;
X scrollup(DEFAULT1(Prenum));
X updatescreen();
X break;
X
X case CTRL('Y'):
X CLEAROP;
X scrolldown(DEFAULT1(Prenum));
X updatescreen();
X break;
X
X case 'z':
X CLEAROP;
X switch (vgetc()) {
X case NL: /* put Curschar at top of screen */
X case CR:
X *Topchar = *Curschar;
X Topchar->index = 0;
X updatescreen();
X break;
X
X case '.': /* put Curschar in middle of screen */
X n = Rows/2;
X goto dozcmd;
X
X case '-': /* put Curschar at bottom of screen */
X n = Rows-1;
X /* fall through */
X
X dozcmd:
X {
X register LPTR *lp = Curschar;
X register int l = 0;
X
X while ((l < n) && (lp != NULL)) {
X l += plines(lp);
X *Topchar = *lp;
X lp = prevline(lp);
X }
X }
X Topchar->index = 0;
X updatescreen();
X break;
X
X default:
X beep();
X }
X break;
X
X /*
X * Control commands
X */
X case ':':
X CLEAROP;
X if ((s = getcmdln(c)) != NULL)
X docmdln(s);
X break;
X
X case K_HELP:
X CLEAROP;
X if (help()) {
X screenclear();
X updatescreen();
X }
X break;
X
X case CTRL('L'):
X CLEAROP;
X screenclear();
X updatescreen();
X break;
X
X
X case CTRL('O'): /* ignored */
X /*
X * A command that's ignored can be useful. We use it at
X * times when we want to postpone redraws. By stuffing
X * in a control-o, redraws get suspended until the editor
X * gets back around to processing input.
X */
X break;
X
X case CTRL('G'):
X CLEAROP;
X fileinfo();
X break;
X
X case K_CGRAVE: /* shorthand command */
X CLEAROP;
X stuffin(":e #\n");
X break;
X
X case 'Z': /* write, if changed, and exit */
X if (vgetc() != 'Z') {
X beep();
X break;
X }
X doxit();
X break;
X
X /*
X * Macro evaluates true if char 'c' is a valid identifier character
X */
X# define IDCHAR(c) (isalpha(c) || isdigit(c) || (c) == '_')
X
X case CTRL(']'): /* :ta to current identifier */
X CLEAROP;
X {
X char ch;
X LPTR save;
X
X save = *Curschar;
X /*
X * First back up to start of identifier. This
X * doesn't match the real vi but I like it a
X * little better and it shouldn't bother anyone.
X */
X ch = gchar(Curschar);
X while (IDCHAR(ch)) {
X if (!oneleft())
X break;
X ch = gchar(Curschar);
X }
X if (!IDCHAR(ch))
X oneright();
X
X stuffin(":ta ");
X /*
X * Now grab the chars in the identifier
X */
X ch = gchar(Curschar);
X while (IDCHAR(ch)) {
X stuffin(mkstr(ch));
X if (!oneright())
X break;
X ch = gchar(Curschar);
X }
X stuffin("\n");
X
X *Curschar = save; /* restore, in case of error */
X }
X break;
X
X /*
X * Character motion commands
X */
X case 'G':
X mtype = MLINE;
X *Curschar = *gotoline(Prenum);
X beginline(TRUE);
X break;
X
X case 'H':
X mtype = MLINE;
X *Curschar = *Topchar;
X for (n = Prenum; n && onedown(1) ;n--)
X ;
X beginline(TRUE);
X break;
X
X case 'M':
X mtype = MLINE;
X *Curschar = *Topchar;
X for (n = 0; n < Rows/2 && onedown(1) ;n++)
X ;
X beginline(TRUE);
X break;
X
X case 'L':
X mtype = MLINE;
X *Curschar = *prevline(Botchar);
X for (n = Prenum; n && oneup(1) ;n--)
X ;
X beginline(TRUE);
X break;
X
X case 'l':
X case K_RARROW:
X case ' ':
X mtype = MCHAR;
X mincl = FALSE;
X n = DEFAULT1(Prenum);
X while (n--) {
X if ( ! oneright() )
X beep();
X }
X set_want_col = TRUE;
X break;
X
X case 'h':
X case K_LARROW:
X case CTRL('H'):
X mtype = MCHAR;
X mincl = FALSE;
X n = DEFAULT1(Prenum);
X while (n--) {
X if ( ! oneleft() )
X beep();
X }
X set_want_col = TRUE;
X break;
X
X case '-':
X flag = TRUE;
X /* fall through */
X
X case 'k':
X case K_UARROW:
X case CTRL('P'):
X mtype = MLINE;
X if ( ! oneup(DEFAULT1(Prenum)) )
X beep();
X if (flag)
X beginline(TRUE);
X break;
X
X case '+':
X case CR:
X case NL:
X flag = TRUE;
X /* fall through */
X
X case 'j':
X case K_DARROW:
X case CTRL('N'):
X mtype = MLINE;
X if ( ! onedown(DEFAULT1(Prenum)) )
X beep();
X if (flag)
X beginline(TRUE);
X break;
X
X /*
X * This is a strange motion command that helps make operators
X * more logical. It is actually implemented, but not documented
X * in the real 'vi'. This motion command actually refers to "the
X * current line". Commands like "dd" and "yy" are really an alternate
X * form of "d_" and "y_". It does accept a count, so "d3_" works to
X * delete 3 lines.
X */
X case '_':
X lineop:
X mtype = MLINE;
X onedown(DEFAULT1(Prenum)-1);
X break;
X
X case '|':
X mtype = MCHAR;
X mincl = TRUE;
X beginline(FALSE);
X if (Prenum > 0)
X *Curschar = *coladvance(Curschar, Prenum-1);
X Curswant = Prenum - 1;
X break;
X
X /*
X * Word Motions
X */
X
X case 'B':
X type = 1;
X /* fall through */
X
X case 'b':
X mtype = MCHAR;
X mincl = FALSE;
X set_want_col = TRUE;
X for (n = DEFAULT1(Prenum); n > 0 ;n--) {
X LPTR *pos;
X
X if ((pos = bck_word(Curschar, type)) == NULL) {
X beep();
X CLEAROP;
X break;
X } else
X *Curschar = *pos;
X }
X break;
X
X case 'W':
X type = 1;
X /* fall through */
X
X case 'w':
X /*
X * This is a little strange. To match what the real vi
X * does, we effectively map 'cw' to 'ce', and 'cW' to 'cE'.
X * This seems impolite at first, but it's really more
X * what we mean when we say 'cw'.
X */
X if (operator == CHANGE)
X goto doecmd;
X
X mtype = MCHAR;
X mincl = FALSE;
X set_want_col = TRUE;
X for (n = DEFAULT1(Prenum); n > 0 ;n--) {
X LPTR *pos;
X
X if ((pos = fwd_word(Curschar, type)) == NULL) {
X beep();
X CLEAROP;
X break;
X } else
X *Curschar = *pos;
X }
X break;
X
X case 'E':
X type = 1;
X /* fall through */
X
X case 'e':
X doecmd:
X mtype = MCHAR;
X mincl = TRUE;
X set_want_col = TRUE;
X for (n = DEFAULT1(Prenum); n > 0 ;n--) {
X LPTR *pos;
X
X /*
X * The first motion gets special treatment if we're
X * do a 'CHANGE'.
X */
X if (n == DEFAULT1(Prenum))
X pos = end_word(Curschar,type,operator==CHANGE);
X else
X pos = end_word(Curschar, type, FALSE);
X
X if (pos == NULL) {
X beep();
X CLEAROP;
X break;
X } else
X *Curschar = *pos;
X }
X break;
X
X case '$':
X mtype = MCHAR;
X mincl = TRUE;
X while ( oneright() )
X ;
X Curswant = 999; /* so we stay at the end */
X break;
X
X case '^':
X mtype = MCHAR;
X mincl = FALSE;
X beginline(TRUE);
X break;
X
X case '0':
X mtype = MCHAR;
X mincl = TRUE;
X beginline(FALSE);
X break;
X
X /*
X * Searches of various kinds
X */
X case '?':
X case '/':
X s = getcmdln(c); /* get the search string */
X
X /*
X * If they backspaced out of the search command,
X * just bag everything.
X */
X if (s == NULL) {
X CLEAROP;
X break;
X }
X
X mtype = MCHAR;
X mincl = FALSE;
X set_want_col = TRUE;
X
X /*
X * If no string given, pass NULL to repeat the prior search.
X * If the search fails, abort any pending operator.
X */
X if (!dosearch(
X (c == '/') ? FORWARD : BACKWARD,
X (*s == NUL) ? NULL : s
X ))
X CLEAROP;
X break;
X
X case 'n':
X mtype = MCHAR;
X mincl = FALSE;
X set_want_col = TRUE;
X if (!repsearch(0))
X CLEAROP;
X break;
X
X case 'N':
X mtype = MCHAR;
X mincl = FALSE;
X set_want_col = TRUE;
X if (!repsearch(1))
X CLEAROP;
X break;
X
X /*
X * Character searches
X */
X case 'T':
X dir = BACKWARD;
X /* fall through */
X
X case 't':
X type = 1;
X goto docsearch;
X
X case 'F':
X dir = BACKWARD;
X /* fall through */
X
X case 'f':
X docsearch:
X mtype = MCHAR;
X mincl = TRUE;
X set_want_col = TRUE;
X if ((nchar = vgetc()) == ESC) /* search char */
X break;
X
X for (n = DEFAULT1(Prenum); n > 0 ;n--) {
X if (!searchc(nchar, dir, type)) {
X CLEAROP;
X beep();
X }
X }
X break;
X
X case ',':
X flag = 1;
X /* fall through */
X
X case ';':
X mtype = MCHAR;
X mincl = TRUE;
X set_want_col = TRUE;
X for (n = DEFAULT1(Prenum); n > 0 ;n--) {
X if (!crepsearch(flag)) {
X CLEAROP;
X beep();
X }
X }
X break;
X
X case '[': /* function searches */
X dir = BACKWARD;
X /* fall through */
X
X case ']':
X mtype = MLINE;
X set_want_col = TRUE;
X if (vgetc() != c) {
X beep();
X CLEAROP;
X break;
X }
X
X if (!findfunc(dir)) {
X beep();
X CLEAROP;
X }
X break;
X
X case '%':
X mtype = MCHAR;
X mincl = TRUE;
X {
X LPTR *pos;
X
X if ((pos = showmatch()) == NULL) {
X beep();
X CLEAROP;
X } else {
X setpcmark();
X *Curschar = *pos;
X set_want_col = TRUE;
X }
X }
X break;
X
X /*
X * Edits
X */
X case '.': /* repeat last change (usually) */
X /*
X * If a delete is in effect, we let '.' help out the same
X * way that '_' helps for some line operations. It's like
X * an 'l', but subtracts one from the count and is inclusive.
X */
X if (operator == DELETE || operator == CHANGE) {
X if (Prenum != 0) {
X n = DEFAULT1(Prenum) - 1;
X while (n--)
X if (! oneright())
X break;
X }
X mtype = MCHAR;
X mincl = TRUE;
X } else { /* a normal 'redo' */
X CLEAROP;
X stuffin(Redobuff);
X }
X break;
X
X case 'u':
X case K_UNDO:
X CLEAROP;
X u_undo();
X break;
X
X case 'U':
X CLEAROP;
X u_lundo();
X break;
X
X case 'x':
X CLEAROP;
X if (lineempty()) /* can't do it on a blank line */
X beep();
X if (Prenum)
X stuffnum(Prenum);
X stuffin("d.");
X break;
X
X case 'X':
X CLEAROP;
X if (!oneleft())
X beep();
X else {
X strcpy(Redobuff, "X");
X u_saveline();
X delchar(TRUE);
X updateline();
X }
X break;
X
X case 'r':
X CLEAROP;
X if (lineempty()) { /* Nothing to replace */
X beep();
X break;
X }
X if ((nchar = vgetc()) == ESC)
X break;
X
X if ((nchar & 0x80) || nchar == CR || nchar == NL) {
X beep();
X break;
X }
X u_saveline();
X
X /* Change current character. */
X pchar(Curschar, nchar);
X
X /* Save stuff necessary to redo it */
X sprintf(Redobuff, "r%c", nchar);
X
X CHANGED;
X updateline();
X break;
X
X case '~': /* swap case */
X if (!P(P_TO)) {
X CLEAROP;
X if (lineempty()) {
X beep();
X break;
X }
X c = gchar(Curschar);
X
X if (isalpha(c)) {
X if (islower(c))
X c = toupper(c);
X else
X c = tolower(c);
X }
X u_saveline();
X
X pchar(Curschar, c); /* Change current character. */
X oneright();
X
X strcpy(Redobuff, "~");
X
X CHANGED;
X updateline();
X }
X#ifdef TILDEOP
X else {
X if (operator == TILDE) /* handle '~~' */
X goto lineop;
X if (Prenum != 0)
X opnum = Prenum;
X startop = *Curschar;
X operator = TILDE;
X }
X#endif
X
X break;
X
X case 'J':
X CLEAROP;
X
X u_save(Curschar->linep->prev, Curschar->linep->next->next);
X
X if (!dojoin(TRUE))
X beep();
X
X strcpy(Redobuff, "J");
X updatescreen();
X break;
X
X /*
X * Inserts
X */
X case 'A':
X set_want_col = TRUE;
X while (oneright())
X ;
X /* fall through */
X
X case 'a':
X CLEAROP;
X /* Works just like an 'i'nsert on the next character. */
X if (!lineempty())
X inc(Curschar);
X u_saveline();
X startinsert(mkstr(c), FALSE);
X break;
X
X case 'I':
X beginline(TRUE);
X /* fall through */
X
X case 'i':
X case K_INSERT:
X CLEAROP;
X u_saveline();
X startinsert(mkstr(c), FALSE);
X break;
X
X case 'o':
X CLEAROP;
X u_save(Curschar->linep, Curschar->linep->next);
X opencmd(FORWARD, TRUE);
X startinsert("o", TRUE);
X break;
X
X case 'O':
X CLEAROP;
X u_save(Curschar->linep->prev, Curschar->linep);
X opencmd(BACKWARD, TRUE);
X startinsert("O", TRUE);
X break;
X
X case 'R':
X CLEAROP;
X u_saveline();
X startinsert("R", FALSE);
X break;
X
X /*
X * Operators
X */
X case 'd':
X if (operator == DELETE) /* handle 'dd' */
X goto lineop;
X if (Prenum != 0)
X opnum = Prenum;
X startop = *Curschar;
X operator = DELETE;
X break;
X
X case 'c':
X if (operator == CHANGE) /* handle 'cc' */
X goto lineop;
X if (Prenum != 0)
X opnum = Prenum;
X startop = *Curschar;
X operator = CHANGE;
X break;
X
X case 'y':
X if (operator == YANK) /* handle 'yy' */
X goto lineop;
X if (Prenum != 0)
X opnum = Prenum;
X startop = *Curschar;
X operator = YANK;
X break;
X
X case '>':
X if (operator == RSHIFT) /* handle >> */
X goto lineop;
X if (Prenum != 0)
X opnum = Prenum;
X startop = *Curschar;
X operator = RSHIFT;
X break;
X
X case '<':
X if (operator == LSHIFT) /* handle << */
X goto lineop;
X if (Prenum != 0)
X opnum = Prenum;
X startop = *Curschar; /* save current position */
X operator = LSHIFT;
X break;
X
X case '!':
X if (operator == FILTER) /* handle '!!' */
X goto lineop;
X if (Prenum != 0)
X opnum = Prenum;
X startop = *Curschar;
X operator = FILTER;
X break;
X
X case 'p':
X doput(FORWARD);
X break;
X
X case 'P':
X doput(BACKWARD);
X break;
X
X /*
X * Abbreviations
X */
X case 'D':
X stuffin("d$");
X break;
X
X case 'Y':
X if (Prenum)
X stuffnum(Prenum);
X stuffin("yy");
X break;
X
X case 'C':
X stuffin("c$");
X break;
X
X case 's': /* substitute characters */
X if (Prenum)
X stuffnum(Prenum);
X stuffin("c.");
X break;
X
X /*
X * Marks
X */
X case 'm':
X CLEAROP;
X if (!setmark(vgetc()))
X beep();
X break;
X
X case '\'':
X flag = TRUE;
X /* fall through */
X
X case '`':
X {
X LPTR mtmp, *mark = getmark(vgetc());
X
X if (mark == NULL) {
X beep();
X CLEAROP;
X } else {
X mtmp = *mark;
X setpcmark();
X *Curschar = mtmp;
X if (flag)
X beginline(TRUE);
X }
X mtype = flag ? MLINE : MCHAR;
X mincl = TRUE; /* ignored if not MCHAR */
X set_want_col = TRUE;
X }
X break;
X
X default:
X CLEAROP;
X beep();
X break;
X }
X
X /*
X * If an operation is pending, handle it...
X */
X if (finish_op) { /* we just finished an operator */
X if (operator == NOP) /* ... but it was cancelled */
X return;
X
X switch (operator) {
X
X case LSHIFT:
X case RSHIFT:
X doshift(operator, c, nchar, Prenum);
X break;
X
X case DELETE:
X dodelete(c, nchar, Prenum);
X break;
X
X case YANK:
X (void) doyank(); /* no redo on yank... */
X break;
X
X case CHANGE:
X dochange(c, nchar, Prenum);
X break;
X
X case FILTER:
X dofilter(c, nchar, Prenum);
X break;
X
X#ifdef TILDEOP
X case TILDE:
X dotilde(c, nchar, Prenum);
X break;
X#endif
X
X default:
X beep();
X }
X operator = NOP;
X }
X}
HE_HATES_THESE_CANS
if test 16909 -ne "`wc -c < 'normal.c'`"
then
echo shar: error transmitting "'normal.c'" '(should have been 16909 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'ops.c'" '(12446 characters)'
if test -f 'ops.c'
then
echo shar: will not over-write existing file "'ops.c'"
else
sed 's/^X//' << \HE_HATES_THESE_CANS > 'ops.c'
X/* $Header: /nw/tony/src/stevie/src/RCS/ops.c,v 1.5 89/08/06 09:50:42 tony Exp $
X *
X * Contains routines that implement the operators in vi. Everything in this
X * file is called only from code in normal.c
X */
X
X#include "stevie.h"
X#include "ops.h"
X
X/*
X * doshift - handle a shift operation
X */
Xvoid
Xdoshift(op, c1, c2, num)
Xint op;
Xchar c1, c2;
Xint num;
X{
X void tabinout();
X LPTR top, bot;
X int nlines;
X char opchar;
X
X top = startop;
X bot = *Curschar;
X
X if (lt(&bot, &top))
X pswap(&top, &bot);
X
X u_save(top.linep->prev, bot.linep->next);
X
X nlines = cntllines(&top, &bot);
X *Curschar = top;
X tabinout((op == LSHIFT), nlines);
X
X /* construct Redo buff */
X opchar = (op == LSHIFT) ? '<' : '>';
X if (num != 0)
X sprintf(Redobuff, "%c%d%c%c", opchar, num, c1, c2);
X else
X sprintf(Redobuff, "%c%c%c", opchar, c1, c2);
X
X /*
X * The cursor position afterward is the prior of the two positions.
X */
X *Curschar = top;
X
X /*
X * If we were on the last char of a line that got shifted left,
X * then move left one so we aren't beyond the end of the line
X */
X if (gchar(Curschar) == NUL && Curschar->index > 0)
X Curschar->index--;
X
X updatescreen();
X
X if (nlines > P(P_RP))
X smsg("%d lines %ced", nlines, opchar);
X}
X
X/*
X * dodelete - handle a delete operation
X */
Xvoid
Xdodelete(c1, c2, num)
Xchar c1, c2;
Xint num;
X{
X LPTR top, bot;
X int nlines;
X register int n;
X
X /*
X * Do a yank of whatever we're about to delete. If there's too much
X * stuff to fit in the yank buffer, then get a confirmation before
X * doing the delete. This is crude, but simple. And it avoids doing
X * a delete of something we can't put back if we want.
X */
X if (!doyank()) {
X msg("yank buffer exceeded: press <y> to confirm");
X if (vgetc() != 'y') {
X msg("delete aborted");
X *Curschar = startop;
X return;
X }
X }
X
X top = startop;
X bot = *Curschar;
X
X if (lt(&bot, &top))
X pswap(&top, &bot);
X
X u_save(top.linep->prev, bot.linep->next);
X
X nlines = cntllines(&top, &bot);
X *Curschar = top;
X cursupdate();
X
X if (mtype == MLINE) {
X delline(nlines, TRUE);
X } else {
X if (!mincl && bot.index != 0)
X dec(&bot);
X
X if (top.linep == bot.linep) { /* del. within line */
X n = bot.index - top.index + 1;
X while (n--)
X if (!delchar(TRUE))
X break;
X } else { /* del. between lines */
X n = Curschar->index;
X while (Curschar->index >= n)
X if (!delchar(TRUE))
X break;
X
X top = *Curschar;
X *Curschar = *nextline(Curschar);
X delline(nlines-2, TRUE);
X Curschar->index = 0;
X n = bot.index + 1;
X while (n--)
X if (!delchar(TRUE))
X break;
X *Curschar = top;
X (void) dojoin(FALSE);
X oneright(); /* we got bumped left up above */
X }
X }
X
X /* construct Redo buff */
X if (num != 0)
X sprintf(Redobuff, "d%d%c%c", num, c1, c2);
X else
X sprintf(Redobuff, "d%c%c", c1, c2);
X
X if (mtype == MCHAR && nlines == 1)
X updateline();
X else
X updatescreen();
X
X if (nlines > P(P_RP))
X smsg("%d fewer lines", nlines);
X}
X
X/*
X * dofilter - handle a filter operation
X */
X
X#define ITMP "viXXXXXX"
X#define OTMP "voXXXXXX"
X
Xstatic char itmp[32];
Xstatic char otmp[32];
X
X
X/*
X * dofilter - filter lines through a command given by the user
X *
X * We use temp files and the system() routine here. This would normally
X * be done using pipes on a UNIX machine, but this is more portable to
X * the machines we usually run on. The system() routine needs to be able
X * to deal with redirection somehow, and should handle things like looking
X * at the PATH env. variable, and adding reasonable extensions to the
X * command name given by the user. All reasonable versions of system()
X * do this.
X */
Xvoid
Xdofilter(c1, c2, num)
Xchar c1, c2;
Xint num;
X{
X char *mktemp();
X static char *lastcmd = NULL;/* the last thing we did */
X char *buff; /* cmd buffer from getcmdln() */
X char cmdln[200]; /* filtering command line */
X LPTR top, bot;
X int nlines;
X
X top = startop;
X bot = *Curschar;
X
X buff = getcmdln('!');
X
X if (buff == NULL) /* user backed out of the command prompt */
X return;
X
X if (*buff == '!') { /* use the 'last' command */
X if (lastcmd == NULL) {
X emsg("No previous command");
X return;
X }
X buff = lastcmd;
X }
X
X /*
X * Remember the current command
X */
X if (lastcmd != NULL)
X free(lastcmd);
X lastcmd = strsave(buff);
X
X if (lt(&bot, &top))
X pswap(&top, &bot);
X
X u_save(top.linep->prev, bot.linep->next);
X
X nlines = cntllines(&top, &bot);
X *Curschar = top;
X cursupdate();
X
X /*
X * 1. Form temp file names
X * 2. Write the lines to a temp file
X * 3. Run the filter command on the temp file
X * 4. Read the output of the command into the buffer
X * 5. Delete the original lines to be filtered
X * 6. Remove the temp files
X */
X
X#ifdef TMPDIR
X strcpy(itmp, TMPDIR);
X strcpy(otmp, TMPDIR);
X#else
X itmp[0] = otmp[0] = NUL;
X#endif
X strcat(itmp, ITMP);
X strcat(otmp, OTMP);
X
X if (mktemp(itmp) == NULL || mktemp(otmp) == NULL) {
X emsg("Can't get temp file names");
X return;
X }
X
X if (!writeit(itmp, &top, &bot)) {
X emsg("Can't create input temp file");
X return;
X }
X
X sprintf(cmdln, "%s <%s >%s", buff, itmp, otmp);
X
X if (system(cmdln) != 0) {
X emsg("Filter command failed");
X remove(ITMP);
X return;
X }
X
X if (readfile(otmp, &bot, TRUE)) {
X emsg("Can't read filter output");
X return;
X }
X
X delline(nlines, TRUE);
X
X remove(itmp);
X remove(otmp);
X
X /* construct Redo buff */
X if (num != 0)
X sprintf(Redobuff, "d%d%c%c", num, c1, c2);
X else
X sprintf(Redobuff, "d%c%c", c1, c2);
X
X updatescreen();
X
X if (nlines > P(P_RP))
X smsg("%d lines filtered", nlines);
X}
X
X#ifdef TILDEOP
Xvoid
Xdotilde(c1, c2, num)
Xchar c1, c2;
Xint num;
X{
X LPTR top, bot;
X register char c;
X
X /* construct Redo buff */
X if (num != 0)
X sprintf(Redobuff, "~%d%c%c", num, c1, c2);
X else
X sprintf(Redobuff, "~%c%c", c1, c2);
X
X top = startop;
X bot = *Curschar;
X
X if (lt(&bot, &top))
X pswap(&top, &bot);
X
X u_save(top.linep->prev, bot.linep->next);
X
X if (mtype == MLINE) {
X top.index = 0;
X bot.index = strlen(bot.linep->s);
X } else {
X if (!mincl) {
X if (bot.index)
X bot.index--;
X }
X }
X
X for (; ltoreq(&top, &bot) ;inc(&top)) {
X /*
X * Swap case through the range
X */
X c = gchar(&top);
X if (isalpha(c)) {
X if (islower(c))
X c = toupper(c);
X else
X c = tolower(c);
X
X pchar(&top, c); /* Change current character. */
X CHANGED;
X }
X }
X *Curschar = startop;
X updatescreen();
X}
X#endif
X
X/*
X * dochange - handle a change operation
X */
Xvoid
Xdochange(c1, c2, num)
Xchar c1, c2;
Xint num;
X{
X char sbuf[16];
X bool_t doappend; /* true if we should do append, not insert */
X bool_t at_eof; /* changing through the end of file */
X LPTR top, bot;
X
X top = startop;
X bot = *Curschar;
X
X if (lt(&bot, &top))
X pswap(&top, &bot);
X
X doappend = endofline(&bot);
X at_eof = (bot.linep->next == Fileend->linep);
X
X dodelete(c1, c2, num);
X
X if (mtype == MLINE) {
X /*
X * If we made a change through the last line of the file,
X * then the cursor got backed up, and we need to open a
X * new line forward, otherwise we go backward.
X */
X if (at_eof)
X opencmd(FORWARD, FALSE);
X else
X opencmd(BACKWARD, FALSE);
X } else {
X if (doappend && !lineempty())
X inc(Curschar);
X }
X
X if (num)
X sprintf(sbuf, "c%d%c%c", num, c1, c2);
X else
X sprintf(sbuf, "c%c%c", c1, c2);
X
X startinsert(sbuf, mtype == MLINE);
X}
X
X#ifndef YBSIZE
X#define YBSIZE 4096
X#endif
X
Xstatic char ybuf[YBSIZE];
Xstatic int ybtype = MBAD;
X
Xbool_t
Xdoyank()
X{
X LPTR top, bot;
X char *yptr = ybuf;
X char *ybend = &ybuf[YBSIZE-1];
X int nlines;
X
X top = startop;
X bot = *Curschar;
X
X if (lt(&bot, &top))
X pswap(&top, &bot);
X
X nlines = cntllines(&top, &bot);
X
X ybtype = mtype; /* set the yank buffer type */
X
X if (mtype == MLINE) {
X top.index = 0;
X bot.index = strlen(bot.linep->s);
X /*
X * The following statement checks for the special case of
X * yanking a blank line at the beginning of the file. If
X * not handled right, we yank an extra char (a newline).
X */
X if (dec(&bot) == -1) {
X ybuf[0] = NUL;
X if (operator == YANK)
X *Curschar = startop;
X return TRUE;
X }
X } else {
X if (!mincl) {
X if (bot.index)
X bot.index--;
X }
X }
X
X for (; ltoreq(&top, &bot) ;inc(&top)) {
X *yptr = (gchar(&top) != NUL) ? gchar(&top) : NL;
X if (++yptr >= ybend) {
X msg("yank too big for buffer");
X ybtype = MBAD;
X return FALSE;
X }
X }
X
X *yptr = NUL;
X
X if (operator == YANK) { /* restore Curschar if really doing yank */
X *Curschar = startop;
X
X if (nlines > P(P_RP))
X smsg("%d lines yanked", nlines);
X }
X
X return TRUE;
X}
X
X/*
X * doput(dir)
X *
X * Put the yank buffer at the current location, using the direction given
X * by 'dir'.
X */
Xvoid
Xdoput(dir)
Xint dir;
X{
X void inslines();
X
X if (ybtype == MBAD) {
X beep();
X return;
X }
X
X u_saveline();
X
X if (ybtype == MLINE)
X inslines(Curschar->linep, dir, ybuf);
X else {
X /*
X * If we did a character-oriented yank, and the buffer
X * contains multiple lines, the situation is more complex.
X * For the moment, we punt, and pretend the user did a
X * line-oriented yank. This doesn't actually happen that
X * often.
X */
X if (strchr(ybuf, NL) != NULL)
X inslines(Curschar->linep, dir, ybuf);
X else {
X char *s;
X int len;
X
X len = strlen(Curschar->linep->s) + strlen(ybuf) + 1;
X s = alloc((unsigned) len);
X strcpy(s, Curschar->linep->s);
X if (dir == FORWARD)
X Curschar->index++;
X strcpy(s + Curschar->index, ybuf);
X strcat(s, &Curschar->linep->s[Curschar->index]);
X free(Curschar->linep->s);
X Curschar->linep->s = s;
X Curschar->linep->size = len;
X updateline();
X }
X }
X
X CHANGED;
X}
X
Xbool_t
Xdojoin(join_cmd)
Xbool_t join_cmd; /* handling a real "join" command? */
X{
X int scol; /* save cursor column */
X int size; /* size of the joined line */
X
X if (nextline(Curschar) == NULL) /* on last line */
X return FALSE;
X
X if (!canincrease(size = strlen(Curschar->linep->next->s)))
X return FALSE;
X
X while (oneright()) /* to end of line */
X ;
X
X strcat(Curschar->linep->s, Curschar->linep->next->s);
X
X /*
X * Delete the following line. To do this we move the cursor
X * there briefly, and then move it back. Don't back up if the
X * delete made us the last line.
X */
X Curschar->linep = Curschar->linep->next;
X scol = Curschar->index;
X
X if (nextline(Curschar) != NULL) {
X delline(1, TRUE);
X Curschar->linep = Curschar->linep->prev;
X } else
X delline(1, TRUE);
X
X Curschar->index = scol;
X
X if (join_cmd)
X oneright(); /* go to first char. of joined line */
X
X if (join_cmd && size != 0) {
X /*
X * Delete leading white space on the joined line
X * and insert a single space.
X */
X while (gchar(Curschar) == ' ' || gchar(Curschar) == TAB)
X delchar(TRUE);
X inschar(' ');
X }
X
X return TRUE;
X}
X
Xvoid
Xstartinsert(initstr, startln)
Xchar *initstr;
Xint startln; /* if set, insert point really at start of line */
X{
X register char *p, c;
X
X *Insstart = *Curschar;
X if (startln)
X Insstart->index = 0;
X Ninsert = 0;
X Insptr = Insbuff;
X for (p=initstr; (c=(*p++))!='\0'; )
X *Insptr++ = c;
X
X if (*initstr == 'R')
X State = REPLACE;
X else
X State = INSERT;
X
X if (P(P_MO))
X msg((State == INSERT) ? "Insert Mode" : "Replace Mode");
X}
X/*
X * tabinout(inout,num)
X *
X * If inout==0, add a tab to the begining of the next num lines.
X * If inout==1, delete a tab from the beginning of the next num lines.
X */
Xstatic void
Xtabinout(inout, num)
Xint inout;
Xint num;
X{
X int ntodo = num;
X LPTR *p;
X
X beginline(FALSE);
X while (ntodo-- > 0) {
X beginline(FALSE);
X if (inout == 0)
X inschar(TAB);
X else {
X if (gchar(Curschar) == TAB)
X delchar(TRUE);
X }
X if ( ntodo > 0 ) {
X if ((p = nextline(Curschar)) != NULL)
X *Curschar = *p;
X else
X break;
X }
X }
X}
X
X/*
X * inslines(lp, dir, buf)
X *
X * Inserts lines in the file from the given buffer. Lines are inserted
X * before or after "lp" according to the given direction flag. Newlines
X * in the buffer result in multiple lines being inserted. The cursor
X * is left on the first of the inserted lines.
X */
Xstatic void
Xinslines(lp, dir, buf)
XLINE *lp;
Xint dir;
Xchar *buf;
X{
X register char *cp = buf;
X register int len;
X char *ep;
X LINE *l, *nc = NULL;
X
X if (dir == BACKWARD)
X lp = lp->prev;
X
X do {
X if ((ep = strchr(cp, NL)) == NULL)
X len = strlen(cp);
X else
X len = ep - cp;
X
X l = newline(len);
X if (len != 0)
X strncpy(l->s, cp, len);
X l->s[len] = NUL;
X
X l->next = lp->next;
X l->prev = lp;
X lp->next->prev = l;
X lp->next = l;
X
X if (nc == NULL)
X nc = l;
X
X lp = lp->next;
X
X cp = ep + 1;
X } while (ep != NULL);
X
X if (dir == BACKWARD) /* fix the top line in case we were there */
X Filemem->linep = Filetop->linep->next;
X
X renum();
X
X updatescreen();
X Curschar->linep = nc;
X Curschar->index = 0;
X}
HE_HATES_THESE_CANS
if test 12446 -ne "`wc -c < 'ops.c'`"
then
echo shar: error transmitting "'ops.c'" '(should have been 12446 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'ops.h'" '(1217 characters)'
if test -f 'ops.h'
then
echo shar: will not over-write existing file "'ops.h'"
else
sed 's/^X//' << \HE_HATES_THESE_CANS > 'ops.h'
X/* $Header: /nw/tony/src/stevie/src/RCS/ops.h,v 1.2 89/07/19 08:08:21 tony Exp $
X *
X * Macros and declarations for the operator code in ops.c
X */
X
X/*
X * Operators
X */
X#define NOP 0 /* no pending operation */
X#define DELETE 1
X#define YANK 2
X#define CHANGE 3
X#define LSHIFT 4
X#define RSHIFT 5
X#define FILTER 6
X#define TILDE 7
X
Xextern int operator; /* current pending operator */
X
X/*
X * When a cursor motion command is made, it is marked as being a character
X * or line oriented motion. Then, if an operator is in effect, the operation
X * becomes character or line oriented accordingly.
X *
X * Character motions are marked as being inclusive or not. Most char.
X * motions are inclusive, but some (e.g. 'w') are not.
X */
X
X/*
X * Cursor motion types
X */
X#define MBAD (-1) /* 'bad' motion type marks unusable yank buf */
X#define MCHAR 0
X#define MLINE 1
X
Xextern int mtype; /* type of the current cursor motion */
Xextern bool_t mincl; /* true if char motion is inclusive */
X
Xextern LPTR startop; /* cursor pos. at start of operator */
X
X/*
X * Functions defined in ops.c
X */
Xvoid doshift(), dodelete(), doput(), dochange(), dofilter();
X#ifdef TILDEOP
Xvoid dotilde();
X#endif
Xbool_t dojoin(), doyank();
Xvoid startinsert();
HE_HATES_THESE_CANS
if test 1217 -ne "`wc -c < 'ops.h'`"
then
echo shar: error transmitting "'ops.h'" '(should have been 1217 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'param.c'" '(3887 characters)'
if test -f 'param.c'
then
echo shar: will not over-write existing file "'param.c'"
else
sed 's/^X//' << \HE_HATES_THESE_CANS > 'param.c'
X/* $Header: /nw/tony/src/stevie/src/RCS/param.c,v 1.10 89/08/02 10:59:10 tony Exp $
X *
X * Code to handle user-settable parameters. This is all pretty much table-
X * driven. To add a new parameter, put it in the params array, and add a
X * macro for it in param.h. If it's a numeric parameter, add any necessary
X * bounds checks to doset(). String parameters aren't currently supported.
X */
X
X#include "stevie.h"
X
Xstruct param params[] = {
X
X { "tabstop", "ts", 8, P_NUM },
X { "scroll", "scroll", 12, P_NUM },
X { "report", "report", 5, P_NUM },
X { "lines", "lines", 25, P_NUM },
X
X { "vbell", "vb", TRUE, P_BOOL },
X { "showmatch", "sm", FALSE, P_BOOL },
X { "wrapscan", "ws", TRUE, P_BOOL },
X { "errorbells", "eb", FALSE, P_BOOL },
X { "showmode", "mo", FALSE, P_BOOL },
X { "backup", "bk", FALSE, P_BOOL },
X { "return", "cr", TRUE, P_BOOL },
X { "list", "list", FALSE, P_BOOL },
X { "ignorecase", "ic", FALSE, P_BOOL },
X { "autoindent", "ai", FALSE, P_BOOL },
X { "number", "nu", FALSE, P_BOOL },
X { "modelines", "ml", FALSE, P_BOOL },
X { "tildeop", "to", FALSE, P_BOOL },
X { "terse", "terse", FALSE, P_BOOL },
X { "", "", 0, 0, } /* end marker */
X
X};
X
Xstatic void showparms();
X
Xvoid
Xdoset(arg)
Xchar *arg; /* parameter string */
X{
X register int i;
X register char *s;
X bool_t did_lines = FALSE;
X bool_t state = TRUE; /* new state of boolean parms. */
X
X if (arg == NULL) {
X showparms(FALSE);
X return;
X }
X if (strncmp(arg, "all", 3) == 0) {
X showparms(TRUE);
X return;
X }
X if (strncmp(arg, "no", 2) == 0) {
X state = FALSE;
X arg += 2;
X }
X
X for (i=0; params[i].fullname[0] != NUL ;i++) {
X s = params[i].fullname;
X if (strncmp(arg, s, strlen(s)) == 0) /* matched full name */
X break;
X s = params[i].shortname;
X if (strncmp(arg, s, strlen(s)) == 0) /* matched short name */
X break;
X }
X
X if (params[i].fullname[0] != NUL) { /* found a match */
X if (params[i].flags & P_NUM) {
X did_lines = (i == P_LI);
X if (arg[strlen(s)] != '=' || state == FALSE)
X emsg("Invalid set of numeric parameter");
X else {
X params[i].value = atoi(arg+strlen(s)+1);
X params[i].flags |= P_CHANGED;
X }
X } else /* boolean */ {
X if (arg[strlen(s)] == '=')
X emsg("Invalid set of boolean parameter");
X else {
X params[i].value = state;
X params[i].flags |= P_CHANGED;
X }
X }
X } else
X emsg("Unrecognized 'set' option");
X
X /*
X * Update the screen in case we changed something like "tabstop"
X * or "list" that will change its appearance.
X */
X updatescreen();
X
X if (did_lines) {
X Rows = P(P_LI);
X screenalloc(); /* allocate new screen buffers */
X screenclear();
X updatescreen();
X }
X /*
X * Check the bounds for numeric parameters here
X */
X if (P(P_TS) <= 0 || P(P_TS) > 32) {
X emsg("Invalid tab size specified");
X P(P_TS) = 8;
X return;
X }
X
X if (P(P_SS) <= 0 || P(P_SS) > Rows) {
X emsg("Invalid scroll size specified");
X P(P_SS) = 12;
X return;
X }
X
X#ifndef TILDEOP
X if (P(P_TO)) {
X emsg("Tilde-operator not enabled");
X P(P_TO) = FALSE;
X return;
X }
X#endif
X /*
X * Check for another argument, and call doset() recursively, if
X * found. If any argument results in an error, no further
X * parameters are processed.
X */
X while (*arg != ' ' && *arg != '\t') { /* skip to next white space */
X if (*arg == NUL)
X return; /* end of parameter list */
X arg++;
X }
X while (*arg == ' ' || *arg == '\t') /* skip to next non-white */
X arg++;
X
X if (*arg)
X doset(arg); /* recurse on next parameter */
X}
X
Xstatic void
Xshowparms(all)
Xbool_t all; /* show ALL parameters */
X{
X register struct param *p;
X char buf[64];
X
X gotocmd(TRUE, 0);
X outstr("Parameters:\r\n");
X
X for (p = ¶ms[0]; p->fullname[0] != NUL ;p++) {
X if (!all && ((p->flags & P_CHANGED) == 0))
X continue;
X if (p->flags & P_BOOL)
X sprintf(buf, "\t%s%s\r\n",
X (p->value ? "" : "no"), p->fullname);
X else
X sprintf(buf, "\t%s=%d\r\n", p->fullname, p->value);
X
X outstr(buf);
X }
X wait_return();
X}
HE_HATES_THESE_CANS
if test 3887 -ne "`wc -c < 'param.c'`"
then
echo shar: error transmitting "'param.c'" '(should have been 3887 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'param.h'" '(1459 characters)'
if test -f 'param.h'
then
echo shar: will not over-write existing file "'param.h'"
else
sed 's/^X//' << \HE_HATES_THESE_CANS > 'param.h'
X/* $Header: /nw/tony/src/stevie/src/RCS/param.h,v 1.8 89/08/02 10:59:35 tony Exp $
X *
X * Settable parameters
X */
X
Xstruct param {
X char *fullname; /* full parameter name */
X char *shortname; /* permissible abbreviation */
X int value; /* parameter value */
X int flags;
X};
X
Xextern struct param params[];
X
X/*
X * Flags
X */
X#define P_BOOL 0x01 /* the parameter is boolean */
X#define P_NUM 0x02 /* the parameter is numeric */
X#define P_CHANGED 0x04 /* the parameter has been changed */
X
X/*
X * The following are the indices in the params array for each parameter
X */
X
X/*
X * Numeric parameters
X */
X#define P_TS 0 /* tab size */
X#define P_SS 1 /* scroll size */
X#define P_RP 2 /* report */
X#define P_LI 3 /* lines */
X
X/*
X * Boolean parameters
X */
X#define P_VB 4 /* visual bell */
X#define P_SM 5 /* showmatch */
X#define P_WS 6 /* wrap scan */
X#define P_EB 7 /* error bells */
X#define P_MO 8 /* show mode */
X#define P_BK 9 /* make backups when writing out files */
X#define P_CR 10 /* use cr-lf to terminate lines on writes */
X#define P_LS 11 /* show tabs and newlines graphically */
X#define P_IC 12 /* ignore case in searches */
X#define P_AI 13 /* auto-indent */
X#define P_NU 14 /* number lines on the screen */
X#define P_ML 15 /* enables mode-lines processing */
X#define P_TO 16 /* if true, tilde is an operator */
X#define P_TE 17 /* ignored; here for compatibility */
X
X/*
X * Macro to get the value of a parameter
X */
X#define P(n) (params[n].value)
HE_HATES_THESE_CANS
if test 1459 -ne "`wc -c < 'param.h'`"
then
echo shar: error transmitting "'param.h'" '(should have been 1459 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'ptrfunc.c'" '(2663 characters)'
if test -f 'ptrfunc.c'
then
echo shar: will not over-write existing file "'ptrfunc.c'"
else
sed 's/^X//' << \HE_HATES_THESE_CANS > 'ptrfunc.c'
X/* $Header: /nw/tony/src/stevie/src/RCS/ptrfunc.c,v 1.5 89/03/11 22:43:12 tony Exp $
X *
X * The routines in this file attempt to imitate many of the operations
X * that used to be performed on simple character pointers and are now
X * performed on LPTR's. This makes it easier to modify other sections
X * of the code. Think of an LPTR as representing a position in the file.
X * Positions can be incremented, decremented, compared, etc. through
X * the functions implemented here.
X */
X
X#include "stevie.h"
X
X/*
X * inc(p)
X *
X * Increment the line pointer 'p' crossing line boundaries as necessary.
X * Return 1 when crossing a line, -1 when at end of file, 0 otherwise.
X */
Xint
Xinc(lp)
Xregister LPTR *lp;
X{
X register char *p;
X
X if (lp && lp->linep)
X p = &(lp->linep->s[lp->index]);
X else
X return -1;
X
X if (*p != NUL) { /* still within line */
X lp->index++;
X return ((p[1] != NUL) ? 0 : 1);
X }
X
X if (lp->linep->next != Fileend->linep) { /* there is a next line */
X lp->index = 0;
X lp->linep = lp->linep->next;
X return 1;
X }
X
X return -1;
X}
X
X/*
X * dec(p)
X *
X * Decrement the line pointer 'p' crossing line boundaries as necessary.
X * Return 1 when crossing a line, -1 when at start of file, 0 otherwise.
X */
Xint
Xdec(lp)
Xregister LPTR *lp;
X{
X if (lp->index > 0) { /* still within line */
X lp->index--;
X return 0;
X }
X
X if (lp->linep->prev != Filetop->linep) { /* there is a prior line */
X lp->linep = lp->linep->prev;
X lp->index = strlen(lp->linep->s);
X return 1;
X }
X
X lp->index = 0; /* stick at first char */
X return -1; /* at start of file */
X}
X
X/*
X * gchar(lp) - get the character at position "lp"
X */
Xint
Xgchar(lp)
Xregister LPTR *lp;
X{
X if (lp && lp->linep)
X return (lp->linep->s[lp->index]);
X else
X return 0;
X}
X
X/*
X * pchar(lp, c) - put character 'c' at position 'lp'
X */
Xvoid
Xpchar(lp, c)
Xregister LPTR *lp;
Xchar c;
X{
X lp->linep->s[lp->index] = c;
X}
X
X/*
X * pswap(a, b) - swap two position pointers
X */
Xvoid
Xpswap(a, b)
Xregister LPTR *a, *b;
X{
X LPTR tmp;
X
X tmp = *a;
X *a = *b;
X *b = tmp;
X}
X
X/*
X * Position comparisons
X */
X
Xbool_t
Xlt(a, b)
Xregister LPTR *a, *b;
X{
X register int an, bn;
X
X an = LINEOF(a);
X bn = LINEOF(b);
X
X if (an != bn)
X return (an < bn);
X else
X return (a->index < b->index);
X}
X
X#if 0
Xbool_t
Xgt(a, b)
XLPTR *a, *b;
X{
X register int an, bn;
X
X an = LINEOF(a);
X bn = LINEOF(b);
X
X if (an != bn)
X return (an > bn);
X else
X return (a->index > b->index);
X}
X#endif
X
Xbool_t
Xequal(a, b)
Xregister LPTR *a, *b;
X{
X return (a->linep == b->linep && a->index == b->index);
X}
X
Xbool_t
Xltoreq(a, b)
Xregister LPTR *a, *b;
X{
X return (lt(a, b) || equal(a, b));
X}
X
X#if 0
Xbool_t
Xgtoreq(a, b)
XLPTR *a, *b;
X{
X return (gt(a, b) || equal(a, b));
X}
X#endif
HE_HATES_THESE_CANS
if test 2663 -ne "`wc -c < 'ptrfunc.c'`"
then
echo shar: error transmitting "'ptrfunc.c'" '(should have been 2663 characters)'
fi
fi # end of overwriting check
# End of shell archive
exit 0
--
More information about the Comp.sources.misc
mailing list