This is fences.c in view mode; [Download] [Up]
/*
*
* fences.c
*
* Match up various fenceposts, like (), [], {}, */ /*, #if, #el, #en
*
* Most code probably by Dan Lawrence or Dave Conroy for MicroEMACS
* Extensions for vile by Paul Fox
*
* $Header: /home/tom/src/vile/RCS/fences.c,v 1.41 1997/02/09 19:41:53 tom Exp $
*
*/
#include "estruct.h"
#include "edef.h"
#if OPT_CFENCE
#define CPP_UNKNOWN -1
#define CPP_IF 0
#define CPP_ELIF 1
#define CPP_ELSE 2
#define CPP_ENDIF 3
#define CurrentChar() \
(is_at_end_of_line(DOT) ? '\n' : char_at(DOT))
#define InDirection(sdir) \
((sdir == REVERSE) ? backchar(FALSE, 1) : forwchar(FALSE, 1))
#define PrevCharIs(c) (DOT.o > 0 && lgetc(DOT.l, DOT.o-1) == c)
#define NextCharIs(c) (DOT.o+1 < llength(DOT.l) && (lgetc(DOT.l, DOT.o+1) == c))
static int comment_fence(int sdir);
static int getfence (int ch, int sdir);
static int simple_fence(int sdir, int ch, int ofence);
static int
cpp_keyword(
LINE *lp,
int off)
{
char temp[NSTRING];
register char *d = temp;
register SIZE_T n;
static const struct {
const char *name;
int code;
} keyword_table[] = {
{ "if", CPP_IF },
{ "ifdef", CPP_IF },
{ "ifndef", CPP_IF },
{ "elif", CPP_ELIF },
{ "else", CPP_ELSE },
{ "endif", CPP_ENDIF }
};
while (off < llength(lp)) {
n = lgetc(lp,off++);
if ((d - temp < sizeof(temp)-2) && isident(n))
*d++ = (char)n;
else
break;
}
*d = EOS;
for (n = 0; n < TABLESIZE(keyword_table); n++)
if (!strcmp(temp, keyword_table[n].name))
return keyword_table[n].code;
return CPP_UNKNOWN;
}
static int
cpp_fence(
int sdir,
int key)
{
int count = 1;
int i, j, this;
/* patch: this should come from arguments */
if (key == CPP_ENDIF)
sdir = REVERSE;
else
sdir = FORWARD;
/* set up for scan */
if (sdir == REVERSE)
DOT.l = lback(DOT.l);
else
DOT.l = lforw(DOT.l);
while (count > 0 && !is_header_line(DOT, curbp)) {
if ((i = firstchar(DOT.l)) >= 0
&& lgetc(DOT.l,i) == '#'
&& (j = nextchar(DOT.l, i+1)) >= 0
&& ((this = cpp_keyword(DOT.l, j)) != CPP_UNKNOWN)) {
int done = FALSE;
switch (this) {
case CPP_IF:
if (sdir == FORWARD) {
count++;
} else {
done = ((count-- == 1) &&
(key != this));
if (done)
count = 0;
}
break;
case CPP_ELIF:
case CPP_ELSE:
done = ((sdir == FORWARD) && (count == 1));
if (done)
count = 0;
break;
case CPP_ENDIF:
if (sdir == FORWARD) {
done = (--count == 0);
} else {
count++;
}
}
if ((count <= 0) || done) {
DOT.o = i;
break;
}
}
if (sdir == REVERSE)
DOT.l = lback(DOT.l);
else
DOT.l = lforw(DOT.l);
if (is_header_line(DOT,curbp) || interrupted())
return FALSE;
}
if (count == 0) {
curwp->w_flag |= WFMOVE;
if (doingopcmd)
regionshape = FULLLINE;
return TRUE;
}
return FALSE;
}
/* the cursor is moved to a matching fence */
int
matchfence(int f, int n)
{
int s = getfence(0, (!f || n > 0) ? FORWARD:REVERSE);
if (s == FALSE)
kbd_alarm();
return s;
}
int
matchfenceback(int f, int n)
{
int s = getfence(0, (!f || n > 0) ? REVERSE:FORWARD);
if (s == FALSE)
kbd_alarm();
return s;
}
#define PAIRED_FENCE_CH -1
int
is_user_fence(int ch, int *sdirp)
{
char *fences = b_val_ptr(curbp,VAL_FENCES);
char *chp, och;
if (!ch)
return 0;
chp = strchr(fences, ch);
if (!chp)
return 0;
if ((chp - fences) & 1) {
/* look for the left fence */
och = chp[-1];
if (sdirp)
*sdirp = REVERSE;
} else {
/* look for the right fence */
och = chp[1];
if (sdirp)
*sdirp = FORWARD;
}
return och;
}
static int
getfence(
int ch, /* fence type to match against */
int sdir) /* direction to scan if we're not on a fence to begin with */
{
MARK oldpos; /* original pointer */
register int ofence = 0; /* open fence */
int s, i;
int key = CPP_UNKNOWN;
char *C_fences, *ptr;
int fch;
/* save the original cursor position */
oldpos = DOT;
/* ch may have been passed, if being used internally */
if (!ch) {
if ((i = firstchar(DOT.l)) < 0) /* offset of first nonblank */
return FALSE; /* line is entirely blank */
if (DOT.o <= i && (ch = lgetc(DOT.l,i)) == '#') {
if (llength(DOT.l) < i+3)
return FALSE;
} else if ((ch = char_at(DOT)) == '/' || ch == '*') {
/* EMPTY */;
} else if (sdir == FORWARD) {
/* get the current character */
if (oldpos.o < llength(oldpos.l)) {
do {
ch = char_at(oldpos);
} while(!is_user_fence(ch, (int *)0) &&
++oldpos.o < llength(oldpos.l));
}
if (is_at_end_of_line(oldpos)) {
return FALSE;
}
} else {
/* get the current character */
if (oldpos.o >= 0) {
do {
ch = char_at(oldpos);
} while(!is_user_fence(ch, (int *)0) &&
--oldpos.o >= 0);
}
if (oldpos.o < 0) {
return FALSE;
}
}
/* we've at least found a fence -- move us that far */
DOT.o = oldpos.o;
}
fch = ch;
/* is it a "special" fence char? */
C_fences = "/*#";
ptr = strchr(C_fences, ch);
if (!ptr) {
ofence = is_user_fence(ch, &sdir);
if (ofence)
fch = PAIRED_FENCE_CH;
}
/* setup proper matching fence */
switch (fch) {
case PAIRED_FENCE_CH:
/* NOTHING */
break;
case '#':
if ((i = firstchar(DOT.l)) < 0)
return FALSE; /* line is entirely blank */
if ((i = nextchar(DOT.l, i+1)) >= 0
&& ((key = cpp_keyword(DOT.l, i)) != CPP_UNKNOWN))
break;
return FALSE;
case '*':
ch = '/';
if (NextCharIs('/')) {
sdir = REVERSE;
forwchar(TRUE,1);
break;
} else if (PrevCharIs('/')) {
sdir = FORWARD;
backchar(TRUE,1);
if (doingopcmd)
pre_op_dot = DOT;
break;
}
return FALSE;
case '/':
if (NextCharIs('*')) {
sdir = FORWARD;
break;
} else if (PrevCharIs('*')) {
sdir = REVERSE;
break;
}
/* FALL THROUGH */
default:
return(FALSE);
}
/* ops are inclusive of the endpoint */
if (doingopcmd && sdir == REVERSE) {
forwchar(TRUE,1);
pre_op_dot = DOT;
backchar(TRUE,1);
}
if (key != CPP_UNKNOWN) { /* we're searching for a cpp keyword */
s = cpp_fence(sdir, key);
} else if (ch == '/') {
s = comment_fence(sdir);
} else {
s = simple_fence(sdir, ch, ofence);
}
if (s == TRUE)
return TRUE;
/* restore the current position */
DOT = oldpos;
return(FALSE);
}
static int
simple_fence(int sdir, int ch, int ofence)
{
int count = 1; /* Assmue that we're sitting at one end of the fence */
int c;
/* scan for fence */
while (InDirection(sdir) && !interrupted()) {
c = CurrentChar();
if (c == ch) {
++count;
} else if (c == ofence) {
if (--count <= 0)
break;
}
}
/* if count is zero, we have a match, move the sucker */
if (count <= 0) {
if (!doingopcmd || doingsweep)
sweephack = TRUE;
else if (sdir == FORWARD)
forwchar(TRUE,1);
curwp->w_flag |= WFMOVE;
return TRUE;
}
return FALSE;
}
static int
comment_fence(int sdir)
{
MARK comstartpos;
int found = FALSE;
int s = FALSE;
int first = TRUE;
comstartpos.l = null_ptr;
while (!found) {
if (!first && CurrentChar() == '/') {
/* is it a comment-end? */
if (PrevCharIs('*')) {
if (sdir == FORWARD) {
found = TRUE;
break;
} else if (comstartpos.l != null_ptr) {
DOT = comstartpos;
found = TRUE;
break;
} else {
return FALSE;
}
}
/* is it a comment start? */
if (sdir == REVERSE && NextCharIs('*')) {
/* remember where we are */
comstartpos = DOT;
}
}
s = InDirection(sdir);
if (s == FALSE) {
if (comstartpos.l != null_ptr) {
DOT = comstartpos;
found = TRUE;
break;
}
return FALSE;
}
if (interrupted())
return FALSE;
first = FALSE;
}
/* if found, move the sucker */
if (found && !first) {
if (!doingopcmd || doingsweep)
sweephack = TRUE;
else if (sdir == FORWARD)
forwchar(TRUE,1);
curwp->w_flag |= WFMOVE;
return TRUE;
}
return FALSE;
}
/* get the indent of the line containing the matching brace/paren. */
int
fmatchindent(int c)
{
int ind;
MK = DOT;
if (getfence(c,REVERSE) == FALSE) {
(void)gomark(FALSE,1);
return previndent((int *)0);
}
ind = indentlen(DOT.l);
(void)gomark(FALSE,1);
return ind;
}
/* Close fences are matched against their partners, and if
on screen the cursor briefly lights there */
void
fmatch(int rch)
{
MARK oldpos; /* original position */
register LINE *toplp; /* top line in current window */
register int count; /* current fence level count */
register char c; /* current character in scan */
int dir, lch;
int backcharfailed = FALSE;
/* get the matching left-fence char, if it exists */
lch = is_user_fence(rch, &dir);
if (lch == 0 || dir != REVERSE)
return;
/* first get the display update out there */
(void)update(FALSE);
/* save the original cursor position */
oldpos = DOT;
/* find the top line and set up for scan */
toplp = lback(curwp->w_line.l);
count = 1;
backchar(TRUE, 2);
/* scan back until we find it, or reach past the top of the window */
while (count > 0 && DOT.l != toplp) {
c = CurrentChar();
if (c == rch)
++count;
if (c == lch)
--count;
if (backchar(FALSE, 1) != TRUE) {
backcharfailed = TRUE;
break;
}
}
/* if count is zero, we have a match, display the sucker */
if (count == 0) {
if (!backcharfailed)
forwchar(FALSE, 1);
if (update(FALSE) == TRUE)
/* the idea is to leave the cursor there for about a
quarter of a second */
catnap(300, FALSE);
}
/* restore the current position */
DOT = oldpos;
}
#endif /* OPT_CFENCE */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.