GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/mg/match.c Lines: 0 58 0.0 %
Date: 2017-11-07 Branches: 0 36 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: match.c,v 1.19 2015/06/03 23:40:01 bcallah Exp $	*/
2
3
/* This file is in the public domain. */
4
5
/*
6
 *	Limited parenthesis matching routines
7
 *
8
 * The hacks in this file implement automatic matching * of (), [], {}, and
9
 * other characters.  It would be better to have a full-blown syntax table,
10
 * but there's enough overhead in the editor as it is.
11
 */
12
13
#include <sys/queue.h>
14
#include <signal.h>
15
#include <stdio.h>
16
17
#include "def.h"
18
#include "key.h"
19
20
static int	balance(void);
21
static void	displaymatch(struct line *, int);
22
23
/*
24
 * Balance table. When balance() encounters a character that is to be
25
 * matched, it first searches this table for a balancing left-side character.
26
 * If the character is not in the table, the character is balanced by itself.
27
 */
28
static struct balance {
29
	char	left, right;
30
} bal[] = {
31
	{ '(', ')' },
32
	{ '[', ']' },
33
	{ '{', '}' },
34
	{ '<', '>' },
35
	{ '\0', '\0' }
36
};
37
38
/*
39
 * Hack to show matching paren.  Self-insert character, then show matching
40
 * character, if any.  Bound to "blink-and-insert".
41
 */
42
int
43
showmatch(int f, int n)
44
{
45
	int	i, s;
46
47
	for (i = 0; i < n; i++) {
48
		if ((s = selfinsert(FFRAND, 1)) != TRUE)
49
			return (s);
50
		/* unbalanced -- warn user */
51
		if (balance() != TRUE)
52
			dobeep();
53
	}
54
	return (TRUE);
55
}
56
57
/*
58
 * Search for and display a matching character.
59
 *
60
 * This routine does the real work of searching backward
61
 * for a balancing character.  If such a balancing character
62
 * is found, it uses displaymatch() to display the match.
63
 */
64
static int
65
balance(void)
66
{
67
	struct line	*clp;
68
	int	 cbo;
69
	int	 c, i, depth;
70
	int	 rbal, lbal;
71
72
	rbal = key.k_chars[key.k_count - 1];
73
74
	/* See if there is a matching character -- default to the same */
75
	lbal = rbal;
76
	for (i = 0; bal[i].right != '\0'; i++)
77
		if (bal[i].right == rbal) {
78
			lbal = bal[i].left;
79
			break;
80
		}
81
82
	/*
83
	 * Move behind the inserted character.	We are always guaranteed
84
	 * that there is at least one character on the line.
85
	 */
86
	clp = curwp->w_dotp;
87
	cbo = curwp->w_doto - 1;
88
89
	/* init nesting depth */
90
	depth = 0;
91
92
	for (;;) {
93
		if (cbo == 0) {
94
			clp = lback(clp);	/* beginning of line	*/
95
			if (clp == curbp->b_headp)
96
				return (FALSE);
97
			cbo = llength(clp) + 1;
98
		}
99
		if (--cbo == llength(clp))
100
			c = '\n';		/* end of line		*/
101
		else
102
			c = lgetc(clp, cbo);	/* somewhere in middle	*/
103
104
		/*
105
		 * Check for a matching character.  If still in a nested
106
		 * level, pop out of it and continue search.  This check
107
		 * is done before the nesting check so single-character
108
		 * matches will work too.
109
		 */
110
		if (c == lbal) {
111
			if (depth == 0) {
112
				displaymatch(clp, cbo);
113
				return (TRUE);
114
			} else
115
				depth--;
116
		}
117
		/* Check for another level of nesting.	 */
118
		if (c == rbal)
119
			depth++;
120
	}
121
	/* NOTREACHED */
122
}
123
124
/*
125
 * Display matching character.  Matching characters that are not in the
126
 * current window are displayed in the echo line. If in the current window,
127
 * move dot to the matching character, sit there a while, then move back.
128
 */
129
static void
130
displaymatch(struct line *clp, int cbo)
131
{
132
	struct line	*tlp;
133
	int	 tbo;
134
	int	 cp;
135
	int	 bufo;
136
	int	 c;
137
	int	 inwindow;
138
	char	 buf[NLINE];
139
140
	/*
141
	 * Figure out if matching char is in current window by
142
	 * searching from the top of the window to dot.
143
	 */
144
	inwindow = FALSE;
145
	for (tlp = curwp->w_linep; tlp != lforw(curwp->w_dotp);
146
	    tlp = lforw(tlp))
147
		if (tlp == clp)
148
			inwindow = TRUE;
149
150
	if (inwindow == TRUE) {
151
		tlp = curwp->w_dotp;	/* save current position */
152
		tbo = curwp->w_doto;
153
154
		curwp->w_dotp = clp;	/* move to new position */
155
		curwp->w_doto = cbo;
156
		curwp->w_rflag |= WFMOVE;
157
158
		update(CMODE);		/* show match */
159
		ttwait(1000);		/* wait for key or 1 second */
160
161
		curwp->w_dotp = tlp;	/* return to old position */
162
		curwp->w_doto = tbo;
163
		curwp->w_rflag |= WFMOVE;
164
		update(CMODE);
165
	} else {
166
		/* match is not in this window, so display line in echo area */
167
		bufo = 0;
168
		for (cp = 0; cp < llength(clp); cp++) {
169
			c = lgetc(clp, cp);
170
			if (c != '\t'
171
#ifdef NOTAB
172
			    || (curbp->b_flag & BFNOTAB)
173
#endif
174
				)
175
				if (ISCTRL(c)) {
176
					buf[bufo++] = '^';
177
					buf[bufo++] = CCHR(c);
178
				} else
179
					buf[bufo++] = c;
180
			else
181
				do {
182
					buf[bufo++] = ' ';
183
				} while (bufo & 7);
184
		}
185
		buf[bufo++] = '\0';
186
		ewprintf("Matches %s", buf);
187
	}
188
}