[BACK]Return to match.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mg

File: [local] / src / usr.bin / mg / match.c (download)

Revision 1.2, Thu Apr 13 06:12:16 2000 UTC (24 years, 2 months ago) by millert
Branch: MAIN
CVS Tags: OPENBSD_2_7_BASE, OPENBSD_2_7
Changes since 1.1: +77 -64 lines

The start of KNF + -Wall.  The code has been run through indent but
needs hand fixup.  I stopped at keymap.c...

/*
 * Name:	MicroEMACS
 *		Limited parenthesis matching routines
 *
 * The hacks in this file implement automatic matching
 * of (), [], {}, and other characters.	 It would be
 * better to have a full-blown syntax table, but there's
 * enough overhead in the editor as it is.
 *
 * Since I often edit Scribe code, I've made it possible to
 * blink arbitrary characters -- just bind delimiter characters
 * to "blink-matching-paren-hack"
 */
#include	"def.h"
#include	"key.h"

static int      balance();
static VOID     displaymatch();

/*
 * Balance table. When balance() encounters a character that is to be
 * matched, it first searches this table for a balancing left-side character.
 * f the character is not in the table, the character is balanced by itself.
 * This is to allow delimiters in Scribe documents to be matched.
 */

static struct balance {
	char            left, right;
}               bal[] = {
	{
		'(', ')'
	},
	{
		'[', ']'
	},
	{
		'{', '}'
	},
	{
		'<', '>'
	},
	{
		'\0', '\0'
	}
};

/*
 * Self-insert character, then show matching character,
 * if any.  Bound to "blink-matching-paren-command".
 */

showmatch(f, n)
{
	register int    i, s;

	if (f & FFRAND)
		return FALSE;
	for (i = 0; i < n; i++) {
		if ((s = selfinsert(FFRAND, 1)) != TRUE)
			return s;
		if (balance() != TRUE)	/* unbalanced -- warn user */
			ttbeep();
	}
	return TRUE;
}

/*
 * Search for and display a matching character.
 *
 * This routine does the real work of searching backward
 * for a balancing character.  If such a balancing character
 * is found, it uses displaymatch() to display the match.
 */

static
balance()
{
	register LINE  *clp;
	register int    cbo;
	int             c;
	int             i;
	int             rbal, lbal;
	int             depth;

	rbal = key.k_chars[key.k_count - 1];

	/* See if there is a matching character -- default to the same */

	lbal = rbal;
	for (i = 0; bal[i].right != '\0'; i++)
		if (bal[i].right == rbal) {
			lbal = bal[i].left;
			break;
		}
	/* Move behind the inserted character.	We are always guaranteed    */
	/* that there is at least one character on the line, since one was  */
	/* just self-inserted by blinkparen.				    */

	clp = curwp->w_dotp;
	cbo = curwp->w_doto - 1;

	depth = 0;		/* init nesting depth		 */

	for (;;) {
		if (cbo == 0) {	/* beginning of line	 */
			clp = lback(clp);
			if (clp == curbp->b_linep)
				return (FALSE);
			cbo = llength(clp) + 1;
		}
		if (--cbo == llength(clp))	/* end of line		 */
			c = '\n';
		else
			c = lgetc(clp, cbo);	/* somewhere in middle	 */

		/* Check for a matching character.  If still in a nested */
		/* level, pop out of it and continue search.  This check */
		/* is done before the nesting check so single-character	 */
		/* matches will work too.				 */
		if (c == lbal) {
			if (depth == 0) {
				displaymatch(clp, cbo);
				return (TRUE);
			} else
				depth--;
		}
		/* Check for another level of nesting.	 */
		if (c == rbal)
			depth++;
	}
	/* NOTREACHED */
}


/*
 * Display matching character.
 * Matching characters that are not in the current window
 * are displayed in the echo line. If in the current
 * window, move dot to the matching character,
 * sit there a while, then move back.
 */

static          VOID
displaymatch(clp, cbo)
	register LINE  *clp;
	register int    cbo;
{
	register LINE  *tlp;
	register int    tbo;
	register int    cp;
	register int    bufo;
	register int    c;
	int             inwindow;
	char            buf[NLINE];

	/* Figure out if matching char is in current window by	 */
	/* searching from the top of the window to dot.		 */

	inwindow = FALSE;
	for (tlp = curwp->w_linep; tlp != lforw(curwp->w_dotp); tlp = lforw(tlp))
		if (tlp == clp)
			inwindow = TRUE;

	if (inwindow == TRUE) {
		tlp = curwp->w_dotp;	/* save current position */
		tbo = curwp->w_doto;

		curwp->w_dotp = clp;	/* move to new position */
		curwp->w_doto = cbo;
		curwp->w_flag |= WFMOVE;

		update();	/* show match */
		sleep(1);	/* wait a bit */

		curwp->w_dotp = tlp;	/* return to old position */
		curwp->w_doto = tbo;
		curwp->w_flag |= WFMOVE;
		update();
	} else {		/* match not in this window so display line
				 * in echo area */
		bufo = 0;
		for (cp = 0; cp < llength(clp); cp++) {	/* expand tabs	 */
			c = lgetc(clp, cp);
			if (c != '\t'
#ifdef	NOTAB
			    || (curbp->b_flag & BFNOTAB)
#endif
				)
				if (ISCTRL(c)) {
					buf[bufo++] = '^';
					buf[bufo++] = CCHR(c);
				} else
					buf[bufo++] = c;
			else
				do {
					buf[bufo++] = ' ';
				} while (bufo & 7);
		}
		buf[bufo++] = '\0';
		ewprintf("Matches %s", buf);
	}
}