AUSAM/source/ded/find.c

#include "ded.h"
#include "match.h"
#include "signal.h"

extern char *cachebuf();
extern char *cachesetup();
int ms_line, ms_col; /* where the match started */
int mf_line, mf_col; /* and where it finished */

matchinterrupt()
 { signal(SIGINTR, ttyinterrupt);
    tdiag("! search abandoned by ^C");
 }

find(pat, direction, p_fline, p_fcol)
struct RE pat[];
int direction, p_fline, p_fcol;
 { register int fline, fcol;
    int startline, startcol, length;
    char *buf;

    fline = p_fline; fcol=p_fcol;

    startline = fline;
    buf = cachesetup(fline);

    if (fcol > (length = strlength(buf)) )
      fcol = length;

    if (fcol==0)
      startcol = fcol = -1;
    else
      startcol=fcol;

    /* if ^C is typed during a search, abort it and leave the
     * command routine.
     */
    signal(SIGINTR, matchinterrupt);

    do
     { if (direction==FORWARD)
	 { if (fcol<0) fcol=0;
	    fcol++;
	    if (fcol>length)
	     { fline++;

		if (fline>maxl)
		 { fline=0; buf = cachesetup(0); }
		else buf = cacheshuffle(FORWARD);

		length=strlength(buf);
		fcol = -1;
	     }
	 }
	else
	if (direction==BACKWARD)
	 { fcol--;
	    if (fcol<0)
	     { fline--;

		if (fline<0)
		 { fline=maxl; buf = cachesetup(maxl); }
		else buf = cacheshuffle(BACKWARD);

		fcol = length = strlength(buf);
	     }
	    if (fcol==0) fcol = -1;
	 }

	if ( match(pat, fline, fcol, buf, &mf_line, &mf_col, &buf) )
	 { ms_col = (fcol<0 ? 0 : fcol);
	    if (mf_col==EOLCOL) mf_col = strlength(buf);
	    signal(SIGINTR, ttyinterrupt);
	    return(true);
	 }
     } while (fline!=startline || fcol!=startcol);

    signal(SIGINTR, ttyinterrupt);
    return(false);
 }

/****************************************************************
 * three procedures to help the matcher in multi-line matches.  *
 *                                                              *
 * Because of the restriction on matches that they all fit on   *
 *      the screen, we can get away with a small buffer         *
 ****************************************************************/

struct CACHE
 { int empty;
    char *cbuf;
 };

struct CACHE *cache;

char *cachesetup(fline)
int fline;
 { register int i;

    /* set up the space on first entry */
    if (auxscreen==0)
     { auxscreen = newscreen(); cache = my_alloc(2*2*NINROWS); }

    for (i=0; i<NINROWS; i++)
     { cache[i].cbuf = auxscreen[i];
	cache[i].empty = true;
     }
    ms_line=fline;
    return(cachebuf(fline));
 }

char *cachebuf(fline)
int fline;
 { register int i;
    i = fline-ms_line;
    if (i<0 || i>=NINROWS)
      editerror("fline (%d) out of range (ms_line %d) in cachebuf",
			fline, ms_line);
    else
    if (cache[i].empty)
     { getline(fline,cache[i].cbuf); cache[i].empty = false; }

    return(cache[i].cbuf);
 }

char *cacheshuffle(direction)
int direction;
 { register int i;
    register char *buf;

    if (direction==FORWARD)
     { buf = cache[0].cbuf;
	for (i=1; i<NINROWS; i++)
	 { cache[i-1].empty = cache[i].empty;
	    cache[i-1].cbuf = cache[i].cbuf;
	 }
	cache[NINROWS-1].empty = true;
	cache[NINROWS-1].cbuf = buf;
	ms_line++;
     }
    else
    if (direction==BACKWARD)
     { buf = cache[NINROWS-1].cbuf;
	for (i=NINROWS-1; i>0; i--)
	 { cache[i].empty = cache[i-1].empty;
	    cache[i].cbuf = cache[i-1].cbuf;
	 }
	cache[0].empty = true;
	cache[0].cbuf = buf;
	ms_line--;
     }

    return(cachebuf(ms_line));
 }