allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (08/20/89)
Posting-number: Volume 8, Issue 7 Submitted-by: tony@cs.utexas.edu@wldrdg.UUCP (Tony Andrews) Archive-name: stevie3.68/part05 #! /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: # screen.c # search.c # stevie.h # term.c # This archive created: Sun Aug 13 11:46:06 1989 export PATH; PATH=/bin:$PATH echo shar: extracting "'screen.c'" '(16083 characters)' if test -f 'screen.c' then echo shar: will not over-write existing file "'screen.c'" else sed 's/^X//' << \HE_HATES_THESE_CANS > 'screen.c' X/* $Header: /nw/tony/src/stevie/src/RCS/screen.c,v 1.8 89/08/02 09:26:33 tony Exp $ X * X * Routines to manipulate the screen representations. X */ X X#include "stevie.h" X X/* X * This gets set if we ignored an update request while input was pending. X * We check this when the input is drained to see if the screen should be X * updated. X */ Xbool_t need_redraw = FALSE; X X/* X * The following variable is set (in filetonext) to the number of physical X * lines taken by the line the cursor is on. We use this to avoid extra X * calls to plines(). The optimized routines lfiletonext() and lnexttoscreen() X * make sure that the size of the cursor line hasn't changed. If so, lines X * below the cursor will move up or down and we need to call the routines X * filetonext() and nexttoscreen() to examine the entire screen. X */ Xstatic int Cline_size; /* size (in rows) of the cursor line */ Xstatic int Cline_row; /* starting row of the cursor line */ X Xstatic char *mkline(); /* calculate line string for "number" mode */ X X/* X * filetonext() X * X * Based on the current value of Topchar, transfer a screenfull of X * stuff from Filemem to Nextscreen, and update Botchar. X */ X Xstatic void Xfiletonext() X{ X register int row, col; X register char *screenp = Nextscreen; X LPTR memp; X LPTR save; /* save pos. in case line won't fit */ X register char *endscreen; X register char *nextrow; X char extra[16]; X int nextra = 0; X register int c; X int n; X bool_t done; /* if TRUE, we hit the end of the file */ X bool_t didline; /* if TRUE, we finished the last line */ X int srow; /* starting row of the current line */ X int lno; /* number of the line we're doing */ X int coff; /* column offset */ X X coff = P(P_NU) ? 8 : 0; X X save = memp = *Topchar; X X if (P(P_NU)) X lno = cntllines(Filemem, Topchar); X X /* X * The number of rows shown is Rows-1. X * The last line is the status/command line. X */ X endscreen = &screenp[(Rows-1)*Columns]; X X done = didline = FALSE; X srow = row = col = 0; X /* X * We go one past the end of the screen so we can find out if the X * last line fit on the screen or not. X */ X while ( screenp <= endscreen && !done) { X X X if (P(P_NU) && col == 0 && memp.index == 0) { X strcpy(extra, mkline(lno++)); X nextra = 8; X } X X /* Get the next character to put on the screen. */ X X /* The 'extra' array contains the extra stuff that is */ X /* inserted to represent special characters (tabs, and */ X /* other non-printable stuff. The order in the 'extra' */ X /* array is reversed. */ X X if ( nextra > 0 ) X c = extra[--nextra]; X else { X c = (unsigned)(0xff & gchar(&memp)); X if (inc(&memp) == -1) X done = 1; X /* when getting a character from the file, we */ X /* may have to turn it into something else on */ X /* the way to putting it into 'Nextscreen'. */ X if ( c == TAB && !P(P_LS) ) { X strcpy(extra," "); X /* tab amount depends on current column */ X nextra = ((P(P_TS)-1) - (col - coff)%P(P_TS)); X c = ' '; X } X else if ( c == NUL && P(P_LS) ) { X extra[0] = NUL; X nextra = 1; X c = '$'; X } else if ( (n = chars[c].ch_size) > 1 ) { X char *p; X nextra = 0; X p = chars[c].ch_str; X /* copy 'ch-str'ing into 'extra' in reverse */ X while ( n > 1 ) X extra[nextra++] = p[--n]; X c = p[0]; X } X } X X if (screenp == endscreen) { X /* X * We're one past the end of the screen. If the X * current character is null, then we really did X * finish, so set didline = TRUE. In either case, X * break out because we're done. X */ X dec(&memp); X if (memp.index != 0 && c == NUL) { X didline = TRUE; X inc(&memp); X } X break; X } X X if ( c == NUL ) { X srow = ++row; X /* X * Save this position in case the next line won't X * fit on the screen completely. X */ X save = memp; X /* get pointer to start of next row */ X nextrow = &Nextscreen[row*Columns]; X /* blank out the rest of this row */ X while ( screenp != nextrow ) X *screenp++ = ' '; X col = 0; X continue; X } X if ( col >= Columns ) { X row++; X col = 0; X } X /* store the character in Nextscreen */ X *screenp++ = c; X col++; X } X /* X * If we didn't hit the end of the file, and we didn't finish X * the last line we were working on, then the line didn't fit. X */ X if (!done && !didline) { X /* X * Clear the rest of the screen and mark the unused lines. X */ X screenp = &Nextscreen[srow * Columns]; X while (screenp < endscreen) X *screenp++ = ' '; X for (; srow < (Rows-1) ;srow++) X Nextscreen[srow * Columns] = '@'; X *Botchar = save; X return; X } X /* make sure the rest of the screen is blank */ X while ( screenp < endscreen ) X *screenp++ = ' '; X /* put '~'s on rows that aren't part of the file. */ X if ( col != 0 ) X row++; X while ( row < Rows ) { X Nextscreen[row*Columns] = '~'; X row++; X } X if (done) /* we hit the end of the file */ X *Botchar = *Fileend; X else X *Botchar = memp; /* FIX - prev? */ X} X X/* X * nexttoscreen X * X * Transfer the contents of Nextscreen to the screen, using Realscreen X * to avoid unnecessary output. X */ Xstatic void Xnexttoscreen() X{ X register char *np = Nextscreen; X register char *rp = Realscreen; X register char *endscreen; X register int row = 0, col = 0; X int gorow = -1, gocol = -1; X X if (anyinput()) { X need_redraw = TRUE; X return; X } X X endscreen = &np[(Rows-1)*Columns]; X X outstr(T_CI); /* disable cursor */ X X for ( ; np < endscreen ; np++,rp++ ) { X /* If desired screen (contents of Nextscreen) does not */ X /* match what's really there, put it there. */ X if ( *np != *rp ) { X /* if we are positioned at the right place, */ X /* we don't have to use windgoto(). */ X if (gocol != col || gorow != row) { X /* X * If we're just off by one, don't send X * an entire esc. seq. (this happens a lot!) X */ X if (gorow == row && gocol+1 == col) { X outchar(*(np-1)); X gocol++; X } else X windgoto(gorow=row,gocol=col); X } X outchar(*rp = *np); X gocol++; X } X if ( ++col >= Columns ) { X col = 0; X row++; X } X } X outstr(T_CV); /* enable cursor again */ X} X X/* X * lfiletonext() - like filetonext() but only for cursor line X * X * Returns true if the size of the cursor line (in rows) hasn't changed. X * This determines whether or not we need to call filetonext() to examine X * the entire screen for changes. X */ Xstatic bool_t Xlfiletonext() X{ X register int row, col; X register char *screenp; X LPTR memp; X register char *nextrow; X char extra[16]; X int nextra = 0; X register int c; X int n; X bool_t eof; X int lno; /* number of the line we're doing */ X int coff; /* column offset */ X X coff = P(P_NU) ? 8 : 0; X X /* X * This should be done more efficiently. X */ X if (P(P_NU)) X lno = cntllines(Filemem, Curschar); X X screenp = Nextscreen + (Cline_row * Columns); X X memp = *Curschar; X memp.index = 0; X X eof = FALSE; X col = 0; X row = Cline_row; X X while (!eof) { X X if (P(P_NU) && col == 0 && memp.index == 0) { X strcpy(extra, mkline(lno)); X nextra = 8; X } X X /* Get the next character to put on the screen. */ X X /* The 'extra' array contains the extra stuff that is */ X /* inserted to represent special characters (tabs, and */ X /* other non-printable stuff. The order in the 'extra' */ X /* array is reversed. */ X X if ( nextra > 0 ) X c = extra[--nextra]; X else { X c = (unsigned)(0xff & gchar(&memp)); X if (inc(&memp) == -1) X eof = TRUE; X /* when getting a character from the file, we */ X /* may have to turn it into something else on */ X /* the way to putting it into 'Nextscreen'. */ X if ( c == TAB && !P(P_LS) ) { X strcpy(extra," "); X /* tab amount depends on current column */ X nextra = ((P(P_TS)-1) - (col - coff)%P(P_TS)); X c = ' '; X } else if ( c == NUL && P(P_LS) ) { X extra[0] = NUL; X nextra = 1; X c = '$'; X } else if ( c != NUL && (n=chars[c].ch_size) > 1 ) { X char *p; X nextra = 0; X p = chars[c].ch_str; X /* copy 'ch-str'ing into 'extra' in reverse */ X while ( n > 1 ) X extra[nextra++] = p[--n]; X c = p[0]; X } X } X X if ( c == NUL ) { X row++; X /* get pointer to start of next row */ X nextrow = &Nextscreen[row*Columns]; X /* blank out the rest of this row */ X while ( screenp != nextrow ) X *screenp++ = ' '; X col = 0; X break; X } X X if ( col >= Columns ) { X row++; X col = 0; X } X /* store the character in Nextscreen */ X *screenp++ = c; X col++; X } X return ((row - Cline_row) == Cline_size); X} X X/* X * lnexttoscreen X * X * Like nexttoscreen() but only for the cursor line. X */ Xstatic void Xlnexttoscreen() X{ X register char *np = Nextscreen + (Cline_row * Columns); X register char *rp = Realscreen + (Cline_row * Columns); X register char *endline; X register int row, col; X int gorow = -1, gocol = -1; X X if (anyinput()) { X need_redraw = TRUE; X return; X } X X endline = np + (Cline_size * Columns); X X row = Cline_row; X col = 0; X X outstr(T_CI); /* disable cursor */ X X for ( ; np < endline ; np++,rp++ ) { X /* If desired screen (contents of Nextscreen) does not */ X /* match what's really there, put it there. */ X if ( *np != *rp ) { X /* if we are positioned at the right place, */ X /* we don't have to use windgoto(). */ X if (gocol != col || gorow != row) { X /* X * If we're just off by one, don't send X * an entire esc. seq. (this happens a lot!) X */ X if (gorow == row && gocol+1 == col) { X outchar(*(np-1)); X gocol++; X } else X windgoto(gorow=row,gocol=col); X } X outchar(*rp = *np); X gocol++; X } X if ( ++col >= Columns ) { X col = 0; X row++; X } X } X outstr(T_CV); /* enable cursor again */ X} X Xstatic char * Xmkline(n) Xregister int n; X{ X static char lbuf[9]; X register int i = 2; X X strcpy(lbuf, " "); X X lbuf[i++] = (n % 10) + '0'; X n /= 10; X if (n != 0) { X lbuf[i++] = (n % 10) + '0'; X n /= 10; X } X if (n != 0) { X lbuf[i++] = (n % 10) + '0'; X n /= 10; X } X if (n != 0) { X lbuf[i++] = (n % 10) + '0'; X n /= 10; X } X if (n != 0) { X lbuf[i++] = (n % 10) + '0'; X n /= 10; X } X return lbuf; X} X X/* X * updateline() - update the line the cursor is on X * X * Updateline() is called after changes that only affect the line that X * the cursor is on. This improves performance tremendously for normal X * insert mode operation. The only thing we have to watch for is when X * the cursor line grows or shrinks around a row boundary. This means X * we have to repaint other parts of the screen appropriately. If X * lfiletonext() returns FALSE, the size of the cursor line (in rows) X * has changed and we have to call updatescreen() to do a complete job. X */ Xvoid Xupdateline() X{ X if (!lfiletonext()) X updatescreen(); /* bag it, do the whole screen */ X else X lnexttoscreen(); X} X Xvoid Xupdatescreen() X{ X extern bool_t interactive; X X if (interactive) { X filetonext(); X nexttoscreen(); X } X} X X/* X * prt_line() - print the given line X */ Xvoid Xprt_line(s) Xchar *s; X{ X register int si = 0; X register int c; X register int col = 0; X X char extra[16]; X int nextra = 0; X int n; X X for (;;) { X X if ( nextra > 0 ) X c = extra[--nextra]; X else { X c = s[si++]; X if ( c == TAB && !P(P_LS) ) { X strcpy(extra, " "); X /* tab amount depends on current column */ X nextra = (P(P_TS) - 1) - col%P(P_TS); X c = ' '; X } else if ( c == NUL && P(P_LS) ) { X extra[0] = NUL; X nextra = 1; X c = '$'; X } else if ( c != NUL && (n=chars[c].ch_size) > 1 ) { X char *p; X X nextra = 0; X p = chars[c].ch_str; X /* copy 'ch-str'ing into 'extra' in reverse */ X while ( n > 1 ) X extra[nextra++] = p[--n]; X c = p[0]; X } X } X X if ( c == NUL ) X break; X X outchar(c); X col++; X } X} X Xvoid Xscreenclear() X{ X register char *rp, *np; X register char *end; X X outstr(T_ED); /* clear the display */ X X rp = Realscreen; X end = Realscreen + Rows * Columns; X np = Nextscreen; X X /* blank out the stored screens */ X while (rp != end) X *rp++ = *np++ = ' '; X} X Xvoid Xcursupdate() X{ X register LPTR *p; X register int icnt, c, nlines; X register int i; X int didinc; X X if (bufempty()) { /* special case - file is empty */ X *Topchar = *Filemem; X *Curschar = *Filemem; X } else if ( LINEOF(Curschar) < LINEOF(Topchar) ) { X nlines = cntllines(Curschar,Topchar); X /* if the cursor is above the top of */ X /* the screen, put it at the top of the screen.. */ X *Topchar = *Curschar; X Topchar->index = 0; X /* ... and, if we weren't very close to begin with, */ X /* we scroll so that the line is close to the middle. */ X if ( nlines > Rows/3 ) { X for (i=0, p = Topchar; i < Rows/3 ;i++, *Topchar = *p) X if ((p = prevline(p)) == NULL) X break; X } else X s_ins(0, nlines-1); X updatescreen(); X } X else if (LINEOF(Curschar) >= LINEOF(Botchar)) { X nlines = cntllines(Botchar,Curschar); X /* If the cursor is off the bottom of the screen, */ X /* put it at the top of the screen.. */ X /* ... and back up */ X if ( nlines > Rows/3 ) { X p = Curschar; X for (i=0; i < (2*Rows)/3 ;i++) X if ((p = prevline(p)) == NULL) X break; X *Topchar = *p; X } else { X scrollup(nlines); X } X updatescreen(); X } X X Cursrow = Curscol = Cursvcol = 0; X for ( p=Topchar; p->linep != Curschar->linep ;p = nextline(p) ) X Cursrow += plines(p); X X Cline_row = Cursrow; X Cline_size = plines(p); X X if (P(P_NU)) X Curscol = 8; X X for (i=0; i <= Curschar->index ;i++) { X c = Curschar->linep->s[i]; X /* A tab gets expanded, depending on the current column */ X if ( c == TAB && !P(P_LS) ) X icnt = P(P_TS) - (Cursvcol % P(P_TS)); X else X icnt = chars[(unsigned)(c & 0xff)].ch_size; X Curscol += icnt; X Cursvcol += icnt; X if ( Curscol >= Columns ) { X Curscol -= Columns; X Cursrow++; X didinc = TRUE; X } X else X didinc = FALSE; X } X if (didinc) X Cursrow--; X X if (c == TAB && State == NORMAL && !P(P_LS)) { X Curscol--; X Cursvcol--; X } else { X Curscol -= icnt; X Cursvcol -= icnt; X } X if (Curscol < 0) X Curscol += Columns; X X if (set_want_col) { X Curswant = Cursvcol; X set_want_col = FALSE; X } X} X X/* X * The rest of the routines in this file perform screen manipulations. X * The given operation is performed physically on the screen. The X * corresponding change is also made to the internal screen image. X * In this way, the editor anticipates the effect of editing changes X * on the appearance of the screen. That way, when we call screenupdate X * a complete redraw isn't usually necessary. Another advantage is that X * we can keep adding code to anticipate screen changes, and in the X * meantime, everything still works. X */ X X/* X * s_ins(row, nlines) - insert 'nlines' lines at 'row' X */ Xvoid Xs_ins(row, nlines) Xint row; Xint nlines; X{ X register char *s, *d; /* src & dest for block copy */ X register char *e; /* end point for copy */ X register int i; X X if (T_IL[0] == NUL) /* can't do it */ X return; X X /* X * It "looks" better if we do all the inserts at once X */ X outstr(T_SC); /* save position */ X windgoto(row, 0); X X for (i=0; i < nlines ;i++) X outstr(T_IL); X X windgoto(Rows-1, 0); /* delete any garbage that may have */ X outstr(T_EL); /* been shifted to the bottom line */ X outstr(T_RC); /* restore the cursor position */ X X /* X * Now do a block move to update the internal screen image X */ X d = Realscreen + (Columns * (Rows - 1)) - 1; X s = d - (Columns * nlines); X e = Realscreen + (Columns * row); X X while (s >= e) X *d-- = *s--; X X /* X * Clear the inserted lines X */ X s = Realscreen + (row * Columns); X e = s + (nlines * Columns); X while (s < e) X *s++ = ' '; X} X X/* X * s_del(row, nlines) - delete 'nlines' lines at 'row' X */ Xvoid Xs_del(row, nlines) Xint row; Xint nlines; X{ X register char *s, *d, *e; X register int i; X X if (T_DL[0] == NUL) /* can't do it */ X return; X X /* delete the lines */ X outstr(T_SC); /* save position */ X windgoto(row, 0); X X for (i=0; i < nlines ;i++) { X outstr(T_DL); /* delete a line */ X if (i == 0) { X windgoto(Rows-2, 0); /* delete any garbage that */ X outstr(T_EL); /* was on the status line */ X windgoto(row, 0); X } X } X outstr(T_RC); /* restore position */ X X /* X * do a block move to update the internal image X */ X d = Realscreen + (row * Columns); X s = d + (nlines * Columns); X e = Realscreen + ((Rows - 1) * Columns); X X while (s < e) X *d++ = *s++; X X while (d < e) /* clear the lines at the bottom */ X *d++ = ' '; X} HE_HATES_THESE_CANS if test 16083 -ne "`wc -c < 'screen.c'`" then echo shar: error transmitting "'screen.c'" '(should have been 16083 characters)' fi fi # end of overwriting check echo shar: extracting "'search.c'" '(18702 characters)' if test -f 'search.c' then echo shar: will not over-write existing file "'search.c'" else sed 's/^X//' << \HE_HATES_THESE_CANS > 'search.c' X/* $Header: /nw/tony/src/stevie/src/RCS/search.c,v 1.16 89/08/06 09:50:51 tony Exp $ X * X * This file contains various searching-related routines. These fall into X * three groups: string searches (for /, ?, n, and N), character searches X * within a single line (for f, F, t, T, etc), and "other" kinds of searches X * like the '%' command, and 'word' searches. X */ X X#include "stevie.h" X#include "regexp.h" /* Henry Spencer's (modified) reg. exp. routines */ X X/* X * String searches X * X * The actual searches are done using Henry Spencer's regular expression X * library. X */ X X#define BEGWORD "([^a-zA-Z0-9_]|^)" /* replaces "\<" in search strings */ X#define ENDWORD "([^a-zA-Z0-9_]|$)" /* likewise replaces "\>" */ X X#define BEGCHAR(c) (islower(c) || isupper(c) || isdigit(c) || ((c) == '_')) X Xbool_t begword; /* does the search include a 'begin word' match */ X X/* X * mapstring(s) - map special backslash sequences X */ Xstatic char * Xmapstring(s) Xregister char *s; X{ X static char ns[80]; X register char *p; X X begword = FALSE; X X for (p = ns; *s ;s++) { X if (*s != '\\') { /* not an escape */ X *p++ = *s; X continue; X } X switch (*++s) { X case '/': X *p++ = '/'; X break; X X case '<': X strcpy(p, BEGWORD); X p += strlen(BEGWORD); X begword = TRUE; X break; X X case '>': X strcpy(p, ENDWORD); X p += strlen(ENDWORD); X break; X X default: X *p++ = '\\'; X *p++ = *s; X break; X } X } X *p++ = NUL; X X return ns; X} X Xstatic char *laststr = NULL; Xstatic int lastsdir; X Xstatic LPTR * Xssearch(dir,str) Xint dir; /* FORWARD or BACKWARD */ Xchar *str; X{ X LPTR *bcksearch(), *fwdsearch(); X LPTR *pos; X char *old_ls = laststr; X X reg_ic = P(P_IC); /* tell the regexp routines how to search */ X X laststr = strsave(str); X lastsdir = dir; X X if (old_ls != NULL) X free(old_ls); X X if (dir == BACKWARD) { X smsg("?%s", laststr); X pos = bcksearch(mapstring(laststr)); X } else { X smsg("/%s", laststr); X pos = fwdsearch(mapstring(laststr)); X } X X /* X * This is kind of a kludge, but its needed to make X * 'beginning of word' searches land on the right place. X */ X if (pos != NULL && begword) { X if (pos->index != 0 || !BEGCHAR(pos->linep->s[0])) X pos->index += 1; X } X return pos; X} X Xbool_t Xdosearch(dir,str) Xint dir; Xchar *str; X{ X LPTR *p; X X if (str == NULL) X str = laststr; X X got_int = FALSE; X X if ((p = ssearch(dir,str)) == NULL) { X if (got_int) X msg("Interrupt"); X else X msg("Pattern not found"); X X got_int = FALSE; X return FALSE; X } else { X LPTR savep; X X cursupdate(); X /* X * if we're backing up, we make sure the line we're on X * is on the screen. X */ X setpcmark(); X *Curschar = savep = *p; X set_want_col = TRUE; X cursupdate(); X X return TRUE; X } X} X X#define OTHERDIR(x) (((x) == FORWARD) ? BACKWARD : FORWARD) X Xbool_t Xrepsearch(flag) Xint flag; X{ X int dir = lastsdir; X bool_t found; X X if ( laststr == NULL ) { X beep(); X return FALSE; X } X X found = dosearch(flag ? OTHERDIR(lastsdir) : lastsdir, laststr); X X /* X * We have to save and restore 'lastsdir' because it gets munged X * by ssearch() and winds up saving the wrong direction from here X * if 'flag' is true. X */ X lastsdir = dir; X X return found; X} X X/* X * regerror - called by regexp routines when errors are detected. X */ Xvoid Xregerror(s) Xchar *s; X{ X emsg(s); X} X Xstatic LPTR * Xfwdsearch(str) Xregister char *str; X{ X static LPTR infile; X register LPTR *p; X regexp *prog; X X register char *s; X register int i; X X if ((prog = regcomp(str)) == NULL) { X emsg("Invalid search string"); X return NULL; X } X X p = Curschar; X i = Curschar->index + 1; X do { X s = p->linep->s + i; X X if (regexec(prog, s, i == 0)) { /* got a match */ X infile.linep = p->linep; X infile.index = (int) (prog->startp[0] - p->linep->s); X free((char *)prog); X return (&infile); X } X i = 0; X X if (got_int) X goto fwdfail; X X } while ((p = nextline(p)) != NULL); X X /* X * If wrapscan isn't set, then don't scan from the beginning X * of the file. Just return failure here. X */ X if (!P(P_WS)) X goto fwdfail; X X /* search from the beginning of the file to Curschar */ X for (p = Filemem; p != NULL ;p = nextline(p)) { X s = p->linep->s; X X if (regexec(prog, s, TRUE)) { /* got a match */ X infile.linep = p->linep; X infile.index = (int) (prog->startp[0] - s); X free((char *)prog); X return (&infile); X } X X if (p->linep == Curschar->linep) X break; X X if (got_int) X goto fwdfail; X } X Xfwdfail: X free((char *)prog); X return NULL; X} X Xstatic LPTR * Xbcksearch(str) Xchar *str; X{ X static LPTR infile; X register LPTR *p = &infile; X register char *s; X register int i; X register char *match; X regexp *prog; X X /* make sure str isn't empty */ X if (str == NULL || *str == NUL) X return NULL; X X if ((prog = regcomp(str)) == NULL) { X emsg("Invalid search string"); X return NULL; X } X X *p = *Curschar; X if (dec(p) == -1) { /* already at start of file? */ X *p = *Fileend; X p->index = strlen(p->linep->s) - 1; X } X X if (begword) /* so we don't get stuck on one match */ X dec(p); X X i = p->index; X X do { X s = p->linep->s; X X if (regexec(prog, s, TRUE)) { /* match somewhere on line */ X X /* X * Now, if there are multiple matches on this line, X * we have to get the last one. Or the last one X * before the cursor, if we're on that line. X */ X match = prog->startp[0]; X X while (regexec(prog, prog->endp[0], FALSE)) { X if ((i >= 0) && ((prog->startp[0] - s) > i)) X break; X match = prog->startp[0]; X } X X if ((i >= 0) && ((match - s) > i)) { X i = -1; X continue; X } X X infile.linep = p->linep; X infile.index = (int) (match - s); X free((char *)prog); X return (&infile); X } X i = -1; X X if (got_int) X goto bckfail; X X } while ((p = prevline(p)) != NULL); X X /* X * If wrapscan isn't set, bag the search now X */ X if (!P(P_WS)) X goto bckfail; X X /* search backward from the end of the file */ X p = prevline(Fileend); X do { X s = p->linep->s; X X if (regexec(prog, s, TRUE)) { /* match somewhere on line */ X X /* X * Now, if there are multiple matches on this line, X * we have to get the last one. X */ X match = prog->startp[0]; X X while (regexec(prog, prog->endp[0], FALSE)) X match = prog->startp[0]; X X infile.linep = p->linep; X infile.index = (int) (match - s); X free((char *)prog); X return (&infile); X } X X if (p->linep == Curschar->linep) X break; X X if (got_int) X goto bckfail; X X } while ((p = prevline(p)) != NULL); X Xbckfail: X free((char *)prog); X return NULL; X} X X/* X * dosub(lp, up, cmd) X * X * Perform a substitution from line 'lp' to line 'up' using the X * command pointed to by 'cmd' which should be of the form: X * X * /pattern/substitution/g X * X * The trailing 'g' is optional and, if present, indicates that multiple X * substitutions should be performed on each line, if applicable. X * The usual escapes are supported as described in the regexp docs. X */ Xvoid Xdosub(lp, up, cmd) XLPTR *lp, *up; Xchar *cmd; X{ X LINE *cp; X char *pat, *sub; X regexp *prog; X int nsubs; X bool_t do_all; /* do multiple substitutions per line */ X X /* X * If no range was given, do the current line. If only one line X * was given, just do that one. X */ X if (lp->linep == NULL) X *up = *lp = *Curschar; X else { X if (up->linep == NULL) X *up = *lp; X } X X pat = ++cmd; /* skip the initial '/' */ X X while (*cmd) { X if (*cmd == '\\') /* next char is quoted */ X cmd += 2; X else if (*cmd == '/') { /* delimiter */ X *cmd++ = NUL; X break; X } else X cmd++; /* regular character */ X } X X if (*pat == NUL) { X emsg("NULL pattern specified"); X return; X } X X sub = cmd; X X do_all = FALSE; X X while (*cmd) { X if (*cmd == '\\') /* next char is quoted */ X cmd += 2; X else if (*cmd == '/') { /* delimiter */ X do_all = (cmd[1] == 'g'); X *cmd++ = NUL; X break; X } else X cmd++; /* regular character */ X } X X reg_ic = P(P_IC); /* set "ignore case" flag appropriately */ X X if ((prog = regcomp(pat)) == NULL) { X emsg("Invalid search string"); X return; X } X X nsubs = 0; X X for (cp = lp->linep; cp != NULL ;cp = cp->next) { X if (regexec(prog, cp->s, TRUE)) { /* a match on this line */ X char *ns, *sns, *p; X X /* X * Get some space for a temporary buffer X * to do the substitution into. X */ X sns = ns = alloc(2048); X *sns = NUL; X X p = cp->s; X X do { X for (ns = sns; *ns ;ns++) X ; X /* X * copy up to the part that matched X */ X while (p < prog->startp[0]) X *ns++ = *p++; X X regsub(prog, sub, ns); X X /* X * continue searching after the match X */ X p = prog->endp[0]; X X } while (regexec(prog, p, FALSE) && do_all); X X for (ns = sns; *ns ;ns++) X ; X X /* X * copy the rest of the line, that didn't match X */ X while (*p) X *ns++ = *p++; X X *ns = NUL; X X free(cp->s); /* free the original line */ X cp->s = strsave(sns); /* and save the modified str */ X cp->size = strlen(cp->s) + 1; X free(sns); /* free the temp buffer */ X nsubs++; X CHANGED; X } X if (cp == up->linep) X break; X } X X if (nsubs) { X updatescreen(); X if (nsubs >= P(P_RP)) X smsg("%d substitution%c", nsubs, (nsubs>1) ? 's' : ' '); X } else X msg("No match"); X X free((char *)prog); X} X X/* X * doglob(cmd) X * X * Execute a global command of the form: X * X * g/pattern/X X * X * where 'x' is a command character, currently one of the following: X * X * d Delete all matching lines X * p Print all matching lines X * X * The command character (as well as the trailing slash) is optional, and X * is assumed to be 'p' if missing. X */ Xvoid Xdoglob(lp, up, cmd) XLPTR *lp, *up; Xchar *cmd; X{ X LINE *cp; X char *pat; X regexp *prog; X int ndone; X char cmdchar = NUL; /* what to do with matching lines */ X X /* X * If no range was given, do every line. If only one line X * was given, just do that one. X */ X if (lp->linep == NULL) { X *lp = *Filemem; X *up = *Fileend; X } else { X if (up->linep == NULL) X *up = *lp; X } X X pat = ++cmd; /* skip the initial '/' */ X X while (*cmd) { X if (*cmd == '\\') /* next char is quoted */ X cmd += 2; X else if (*cmd == '/') { /* delimiter */ X cmdchar = cmd[1]; X *cmd++ = NUL; X break; X } else X cmd++; /* regular character */ X } X if (cmdchar == NUL) X cmdchar = 'p'; X X reg_ic = P(P_IC); /* set "ignore case" flag appropriately */ X X if (cmdchar != 'd' && cmdchar != 'p') { X emsg("Invalid command character"); X return; X } X X if ((prog = regcomp(pat)) == NULL) { X emsg("Invalid search string"); X return; X } X X msg(""); X ndone = 0; X got_int = FALSE; X X for (cp = lp->linep; cp != NULL && !got_int ;cp = cp->next) { X if (regexec(prog, cp->s, TRUE)) { /* a match on this line */ X switch (cmdchar) { X X case 'd': /* delete the line */ X if (Curschar->linep != cp) { X LPTR savep; X X savep = *Curschar; X Curschar->linep = cp; X Curschar->index = 0; X delline(1, FALSE); X *Curschar = savep; X } else X delline(1, FALSE); X break; X X case 'p': /* print the line */ X prt_line(cp->s); X outstr("\r\n"); X break; X } X ndone++; X } X if (cp == up->linep) X break; X } X X if (ndone) { X switch (cmdchar) { X X case 'd': X updatescreen(); X if (ndone >= P(P_RP) || got_int) X smsg("%s%d fewer line%c", X got_int ? "Interrupt: " : "", X ndone, X (ndone > 1) ? 's' : ' '); X break; X X case 'p': X wait_return(); X break; X } X } else { X if (got_int) X msg("Interrupt"); X else X msg("No match"); X } X X got_int = FALSE; X free((char *)prog); X} X X/* X * Character Searches X */ X Xstatic char lastc = NUL; /* last character searched for */ Xstatic int lastcdir; /* last direction of character search */ Xstatic int lastctype; /* last type of search ("find" or "to") */ X X/* X * searchc(c, dir, type) X * X * Search for character 'c', in direction 'dir'. If type is 0, move to X * the position of the character, otherwise move to just before the char. X */ Xbool_t Xsearchc(c, dir, type) Xchar c; Xint dir; Xint type; X{ X LPTR save; X X save = *Curschar; /* save position in case we fail */ X lastc = c; X lastcdir = dir; X lastctype = type; X X /* X * On 'to' searches, skip one to start with so we can repeat X * searches in the same direction and have it work right. X */ X if (type) X (dir == FORWARD) ? oneright() : oneleft(); X X while ( (dir == FORWARD) ? oneright() : oneleft() ) { X if (gchar(Curschar) == c) { X if (type) X (dir == FORWARD) ? oneleft() : oneright(); X return TRUE; X } X } X *Curschar = save; X return FALSE; X} X Xbool_t Xcrepsearch(flag) Xint flag; X{ X int dir = lastcdir; X int rval; X X if (lastc == NUL) X return FALSE; X X rval = searchc(lastc, flag ? OTHERDIR(lastcdir) : lastcdir, lastctype); X X lastcdir = dir; /* restore dir., since it may have changed */ X X return rval; X} X X/* X * "Other" Searches X */ X X/* X * showmatch - move the cursor to the matching paren or brace X */ XLPTR * Xshowmatch() X{ X static LPTR pos; X int (*move)(), inc(), dec(); X char initc = gchar(Curschar); /* initial char */ X char findc; /* terminating char */ X char c; X int count = 0; X X pos = *Curschar; /* set starting point */ X X switch (initc) { X X case '(': X findc = ')'; X move = inc; X break; X case ')': X findc = '('; X move = dec; X break; X case '{': X findc = '}'; X move = inc; X break; X case '}': X findc = '{'; X move = dec; X break; X case '[': X findc = ']'; X move = inc; X break; X case ']': X findc = '['; X move = dec; X break; X default: X return (LPTR *) NULL; X } X X while ((*move)(&pos) != -1) { /* until end of file */ X c = gchar(&pos); X if (c == initc) X count++; X else if (c == findc) { X if (count == 0) X return &pos; X count--; X } X } X return (LPTR *) NULL; /* never found it */ X} X X/* X * findfunc(dir) - Find the next function in direction 'dir' X * X * Return TRUE if a function was found. X */ Xbool_t Xfindfunc(dir) Xint dir; X{ X LPTR *curr; X X curr = Curschar; X X do { X curr = (dir == FORWARD) ? nextline(curr) : prevline(curr); X X if (curr != NULL && curr->linep->s[0] == '{') { X setpcmark(); X *Curschar = *curr; X return TRUE; X } X } while (curr != NULL); X X return FALSE; X} X X/* X * The following routines do the word searches performed by the X * 'w', 'W', 'b', 'B', 'e', and 'E' commands. X */ X X/* X * To perform these searches, characters are placed into one of three X * classes, and transitions between classes determine word boundaries. X * X * The classes are: X * X * 0 - white space X * 1 - letters, digits, and underscore X * 2 - everything else X */ X Xstatic int stype; /* type of the word motion being performed */ X X#define C0(c) (((c) == ' ') || ((c) == '\t') || ((c) == NUL)) X#define C1(c) (isalpha(c) || isdigit(c) || ((c) == '_')) X X/* X * cls(c) - returns the class of character 'c' X * X * The 'type' of the current search modifies the classes of characters X * if a 'W', 'B', or 'E' motion is being done. In this case, chars. from X * class 2 are reported as class 1 since only white space boundaries are X * of interest. X */ Xstatic int Xcls(c) Xchar c; X{ X if (C0(c)) X return 0; X X if (C1(c)) X return 1; X X /* X * If stype is non-zero, report these as class 1. X */ X return (stype == 0) ? 2 : 1; X} X X X/* X * fwd_word(pos, type) - move forward one word X * X * Returns the resulting position, or NULL if EOF was reached. X */ XLPTR * Xfwd_word(p, type) XLPTR *p; Xint type; X{ X static LPTR pos; X int sclass = cls(gchar(p)); /* starting class */ X X pos = *p; X X stype = type; X X /* X * We always move at least one character. X */ X if (inc(&pos) == -1) X return NULL; X X if (sclass != 0) { X while (cls(gchar(&pos)) == sclass) { X if (inc(&pos) == -1) X return NULL; X } X /* X * If we went from 1 -> 2 or 2 -> 1, return here. X */ X if (cls(gchar(&pos)) != 0) X return &pos; X } X X /* We're in white space; go to next non-white */ X X while (cls(gchar(&pos)) == 0) { X /* X * We'll stop if we land on a blank line X */ X if (pos.index == 0 && pos.linep->s[0] == NUL) X break; X X if (inc(&pos) == -1) X return NULL; X } X X return &pos; X} X X/* X * bck_word(pos, type) - move backward one word X * X * Returns the resulting position, or NULL if EOF was reached. X */ XLPTR * Xbck_word(p, type) XLPTR *p; Xint type; X{ X static LPTR pos; X int sclass = cls(gchar(p)); /* starting class */ X X pos = *p; X X stype = type; X X if (dec(&pos) == -1) X return NULL; X X /* X * If we're in the middle of a word, we just have to X * back up to the start of it. X */ X if (cls(gchar(&pos)) == sclass && sclass != 0) { X /* X * Move backward to start of the current word X */ X while (cls(gchar(&pos)) == sclass) { X if (dec(&pos) == -1) X return NULL; X } X inc(&pos); /* overshot - forward one */ X return &pos; X } X X /* X * We were at the start of a word. Go back to the start X * of the prior word. X */ X X while (cls(gchar(&pos)) == 0) { /* skip any white space */ X /* X * We'll stop if we land on a blank line X */ X if (pos.index == 0 && pos.linep->s[0] == NUL) X return &pos; X X if (dec(&pos) == -1) X return NULL; X } X X sclass = cls(gchar(&pos)); X X /* X * Move backward to start of this word. X */ X while (cls(gchar(&pos)) == sclass) { X if (dec(&pos) == -1) X return NULL; X } X inc(&pos); /* overshot - forward one */ X X return &pos; X} X X/* X * end_word(pos, type, in_change) - move to the end of the word X * X * There is an apparent bug in the 'e' motion of the real vi. At least X * on the System V Release 3 version for the 80386. Unlike 'b' and 'w', X * the 'e' motion crosses blank lines. When the real vi crosses a blank X * line in an 'e' motion, the cursor is placed on the FIRST character X * of the next non-blank line. The 'E' command, however, works correctly. X * Since this appears to be a bug, I have not duplicated it here. X * X * There's a strange special case here that the 'in_change' parameter X * helps us deal with. Vi effectively turns 'cw' into 'ce'. If we're on X * a word with only one character, we need to stick at the current X * position so we don't change two words. X * X * Returns the resulting position, or NULL if EOF was reached. X */ XLPTR * Xend_word(p, type, in_change) XLPTR *p; Xint type; Xbool_t in_change; X{ X static LPTR pos; X int sclass = cls(gchar(p)); /* starting class */ X X pos = *p; X X stype = type; X X if (inc(&pos) == -1) X return NULL; X X /* X * If we're in the middle of a word, we just have to X * move to the end of it. X */ X if (cls(gchar(&pos)) == sclass && sclass != 0) { X /* X * Move forward to end of the current word X */ X while (cls(gchar(&pos)) == sclass) { X if (inc(&pos) == -1) X return NULL; X } X dec(&pos); /* overshot - forward one */ X return &pos; X } X X /* X * We were at the end of a word. Go to the end of the next X * word, unless we're doing a change. In that case we stick X * at the end of the current word. X */ X if (in_change) X return p; X X while (cls(gchar(&pos)) == 0) { /* skip any white space */ X if (inc(&pos) == -1) X return NULL; X } X X sclass = cls(gchar(&pos)); X X /* X * Move forward to end of this word. X */ X while (cls(gchar(&pos)) == sclass) { X if (inc(&pos) == -1) X return NULL; X } X dec(&pos); /* overshot - forward one */ X X return &pos; X} HE_HATES_THESE_CANS if test 18702 -ne "`wc -c < 'search.c'`" then echo shar: error transmitting "'search.c'" '(should have been 18702 characters)' fi fi # end of overwriting check echo shar: extracting "'stevie.h'" '(4232 characters)' if test -f 'stevie.h' then echo shar: will not over-write existing file "'stevie.h'" else sed 's/^X//' << \HE_HATES_THESE_CANS > 'stevie.h' X/* X * $Header: /nw/tony/src/stevie/src/RCS/stevie.h,v 1.19 89/07/12 21:33:32 tony Exp $ X * X * Main header file included by all source files. X */ X X#include "env.h" /* defines to establish the compile-time environment */ X X#include <stdio.h> X#include <ctype.h> X X#ifdef BSD X X#include <strings.h> X#define strchr index X X#else X X#ifdef MINIX X Xextern char *strchr(); Xextern char *strrchr(); Xextern char *strcpy(); Xextern char *strcat(); Xextern int strlen(); X X#else X#include <string.h> X#endif X X#endif X X#include "ascii.h" X#include "keymap.h" X#include "param.h" X#include "term.h" X Xextern char *strchr(); X X#define NORMAL 0 X#define CMDLINE 1 X#define INSERT 2 X#define REPLACE 3 X#define FORWARD 4 X#define BACKWARD 5 X X/* X * Boolean type definition and constants X */ Xtypedef short bool_t; X X#ifndef TRUE X#define FALSE (0) X#define TRUE (1) X#endif X X/* X * SLOP is the amount of extra space we get for text on a line during X * editing operations that need more space. This keeps us from calling X * malloc every time we get a character during insert mode. No extra X * space is allocated when the file is initially read. X */ X#define SLOP 10 X X/* X * LINEINC is the gap we leave between the artificial line numbers. This X * helps to avoid renumbering all the lines every time a new line is X * inserted. X */ X#define LINEINC 10 X X#define CHANGED Changed=TRUE X#define UNCHANGED Changed=FALSE X Xstruct line { X struct line *prev, *next; /* previous and next lines */ X char *s; /* text for this line */ X int size; /* actual size of space at 's' */ X unsigned long num; /* line "number" */ X}; X X#define LINEOF(x) ((x)->linep->num) X Xstruct lptr { X struct line *linep; /* line we're referencing */ X int index; /* position within that line */ X}; X Xtypedef struct line LINE; Xtypedef struct lptr LPTR; X Xstruct charinfo { X char ch_size; X char *ch_str; X}; X Xextern struct charinfo chars[]; X Xextern int State; Xextern int Rows; Xextern int Columns; Xextern char *Realscreen; Xextern char *Nextscreen; Xextern char *Filename; Xextern LPTR *Filemem; Xextern LPTR *Filetop; Xextern LPTR *Fileend; Xextern LPTR *Topchar; Xextern LPTR *Botchar; Xextern LPTR *Curschar; Xextern LPTR *Insstart; Xextern int Cursrow, Curscol, Cursvcol, Curswant; Xextern bool_t set_want_col; Xextern int Prenum; Xextern bool_t Changed; Xextern char Redobuff[], Insbuff[]; Xextern char *Insptr; Xextern int Ninsert; Xextern bool_t got_int; X Xextern char *malloc(), *strcpy(); X X/* X * alloc.c X */ Xchar *alloc(), *strsave(), *mkstr(); Xvoid screenalloc(), filealloc(), freeall(); XLINE *newline(); Xbool_t bufempty(), buf1line(), lineempty(), endofline(), canincrease(); X X/* X * cmdline.c X */ Xvoid docmdln(), dotag(), msg(), emsg(), smsg(), gotocmd(), wait_return(); Xchar *getcmdln(); X X/* X * edit.c X */ Xvoid edit(), insertchar(), getout(), scrollup(), scrolldown(), beginline(); Xbool_t oneright(), oneleft(), oneup(), onedown(); X X/* X * fileio.c X */ Xvoid filemess(), renum(); Xbool_t readfile(), writeit(); X X/* X * help.c X */ Xbool_t help(); X X/* X * linefunc.c X */ XLPTR *nextline(), *prevline(), *coladvance(); X X/* X * main.c X */ Xvoid stuffin(), stuffnum(); Xvoid do_mlines(); Xint vgetc(); Xbool_t anyinput(); X X/* X * mark.c X */ Xvoid setpcmark(), clrall(), clrmark(); Xbool_t setmark(); XLPTR *getmark(); X X/* X * misccmds.c X */ Xvoid opencmd(), fileinfo(), inschar(), delline(); Xbool_t delchar(); Xint cntllines(), plines(); XLPTR *gotoline(); X X/* X * normal.c X */ Xvoid normal(); X X/* X * param.c X */ Xvoid doset(); X X/* X * ptrfunc.c X */ Xint inc(), dec(); Xint gchar(); Xvoid pchar(), pswap(); Xbool_t lt(), equal(), ltoreq(); X#if 0 X/* not currently used */ Xbool_t gtoreq(), gt(); X#endif X X/* X * screen.c X */ Xvoid updatescreen(), updateline(); Xvoid screenclear(), cursupdate(); Xvoid s_ins(), s_del(); Xvoid prt_line(); X X/* X * search.c X */ Xvoid dosub(), doglob(); Xbool_t searchc(), crepsearch(), findfunc(), dosearch(), repsearch(); XLPTR *showmatch(); XLPTR *fwd_word(), *bck_word(), *end_word(); X X/* X * undo.c X */ Xvoid u_save(), u_saveline(), u_clear(); Xvoid u_lcheck(), u_lundo(); Xvoid u_undo(); X X/* X * Machine-dependent routines. X */ Xint inchar(); Xvoid flushbuf(); Xvoid outchar(), outstr(), beep(); Xchar *fixname(); X#ifndef OS2 X#ifndef DOS Xvoid remove(), rename(); X#endif X#endif Xvoid windinit(), windexit(), windgoto(); Xvoid delay(); Xvoid doshell(); HE_HATES_THESE_CANS if test 4232 -ne "`wc -c < 'stevie.h'`" then echo shar: error transmitting "'stevie.h'" '(should have been 4232 characters)' fi fi # end of overwriting check echo shar: extracting "'term.c'" '(1685 characters)' if test -f 'term.c' then echo shar: will not over-write existing file "'term.c'" else sed 's/^X//' << \HE_HATES_THESE_CANS > 'term.c' X/* $Header: /nw/tony/src/stevie/src/RCS/term.c,v 1.4 89/03/11 22:43:55 tony Exp $ X * X * Termcap initialization (optional). X */ X X#include <stdio.h> X#include "stevie.h" X X#ifdef TERMCAP X Xstatic char buf[1024]; /* termcap entry read here */ Xstatic char cap[256]; /* capability strings go in here */ X Xchar *T_EL; /* erase the entire current line */ Xchar *T_IL; /* insert one line */ Xchar *T_DL; /* delete one line */ Xchar *T_SC; /* save the cursor position */ Xchar *T_ED; /* erase display (may optionally home cursor) */ Xchar *T_RC; /* restore the cursor position */ Xchar *T_CI; /* invisible cursor (very optional) */ Xchar *T_CV; /* visible cursor (very optional) */ X Xchar *T_CM; /* cursor motion string */ X Xextern int tgetent(), tgetnum(); Xextern char *tgetstr(); Xextern char *getenv(); X Xint Xt_init() X{ X char *term; X int n; X char *cp = cap; X X if ((term = getenv("TERM")) == NULL) X return 0; X X if (tgetent(buf, term) != 1) X return 0; X X if ((n = tgetnum("li")) == -1) X return 0; X else X P(P_LI) = Rows = n; X X if ((n = tgetnum("co")) == -1) X return 0; X else X Columns = n; X X /* X * Get mandatory capability strings. X */ X if ((T_CM = tgetstr("cm", &cp)) == NULL) X return 0; X X if ((T_EL = tgetstr("ce", &cp)) == NULL) X return 0; X X if ((T_ED = tgetstr("cl", &cp)) == NULL) X return 0; X X /* X * Optional capabilities. X */ X if ((T_IL = tgetstr("al", &cp)) == NULL) X T_IL = ""; X X if ((T_DL = tgetstr("dl", &cp)) == NULL) X T_DL = ""; X X if ((T_SC = tgetstr("sc", &cp)) == NULL) X T_SC = ""; X X if ((T_RC = tgetstr("rc", &cp)) == NULL) X T_RC = ""; X X if ((T_CI = tgetstr("vi", &cp)) == NULL) X T_CI = ""; X X if ((T_CV = tgetstr("ve", &cp)) == NULL) X T_CV = ""; X X return 1; X} X X#endif HE_HATES_THESE_CANS if test 1685 -ne "`wc -c < 'term.c'`" then echo shar: error transmitting "'term.c'" '(should have been 1685 characters)' fi fi # end of overwriting check # End of shell archive exit 0 --