xref: /freebsd-src/contrib/less/brac.c (revision c77c488926555ca344ae3a417544cf7a720e1de1)
1a5f0fb15SPaul Saab /*
2*c77c4889SXin LI  * Copyright (C) 1984-2024  Mark Nudelman
3a5f0fb15SPaul Saab  *
4a5f0fb15SPaul Saab  * You may distribute under the terms of either the GNU General Public
5a5f0fb15SPaul Saab  * License or the Less License, as specified in the README file.
6a5f0fb15SPaul Saab  *
796e55cc7SXin LI  * For more information, see the README file.
8a5f0fb15SPaul Saab  */
9a5f0fb15SPaul Saab 
10a5f0fb15SPaul Saab 
11a5f0fb15SPaul Saab /*
12a5f0fb15SPaul Saab  * Routines to perform bracket matching functions.
13a5f0fb15SPaul Saab  */
14a5f0fb15SPaul Saab 
15a5f0fb15SPaul Saab #include "less.h"
16a5f0fb15SPaul Saab #include "position.h"
17a5f0fb15SPaul Saab 
18a5f0fb15SPaul Saab /*
19a5f0fb15SPaul Saab  * Try to match the n-th open bracket
20a5f0fb15SPaul Saab  *  which appears in the top displayed line (forwdir),
21a5f0fb15SPaul Saab  * or the n-th close bracket
22a5f0fb15SPaul Saab  *  which appears in the bottom displayed line (!forwdir).
23a5f0fb15SPaul Saab  * The characters which serve as "open bracket" and
24a5f0fb15SPaul Saab  * "close bracket" are given.
25a5f0fb15SPaul Saab  */
26d713e089SXin LI public void match_brac(char obrac, char cbrac, int forwdir, int n)
27a5f0fb15SPaul Saab {
281ea31627SRobert Watson 	int c;
291ea31627SRobert Watson 	int nest;
30a5f0fb15SPaul Saab 	POSITION pos;
31f6b74a7dSXin LI 	int (*chget)();
32a5f0fb15SPaul Saab 
33f6b74a7dSXin LI 	extern int ch_forw_get(), ch_back_get();
34a5f0fb15SPaul Saab 
35a5f0fb15SPaul Saab 	/*
36a5f0fb15SPaul Saab 	 * Seek to the line containing the open bracket.
37a5f0fb15SPaul Saab 	 * This is either the top or bottom line on the screen,
38a5f0fb15SPaul Saab 	 * depending on the type of bracket.
39a5f0fb15SPaul Saab 	 */
40a5f0fb15SPaul Saab 	pos = position((forwdir) ? TOP : BOTTOM);
41a5f0fb15SPaul Saab 	if (pos == NULL_POSITION || ch_seek(pos))
42a5f0fb15SPaul Saab 	{
43a5f0fb15SPaul Saab 		if (forwdir)
44a5f0fb15SPaul Saab 			error("Nothing in top line", NULL_PARG);
45a5f0fb15SPaul Saab 		else
46a5f0fb15SPaul Saab 			error("Nothing in bottom line", NULL_PARG);
47a5f0fb15SPaul Saab 		return;
48a5f0fb15SPaul Saab 	}
49a5f0fb15SPaul Saab 
50a5f0fb15SPaul Saab 	/*
51a5f0fb15SPaul Saab 	 * Look thru the line to find the open bracket to match.
52a5f0fb15SPaul Saab 	 */
53a5f0fb15SPaul Saab 	do
54a5f0fb15SPaul Saab 	{
55a5f0fb15SPaul Saab 		if ((c = ch_forw_get()) == '\n' || c == EOI)
56a5f0fb15SPaul Saab 		{
57a5f0fb15SPaul Saab 			if (forwdir)
58a5f0fb15SPaul Saab 				error("No bracket in top line", NULL_PARG);
59a5f0fb15SPaul Saab 			else
60a5f0fb15SPaul Saab 				error("No bracket in bottom line", NULL_PARG);
61a5f0fb15SPaul Saab 			return;
62a5f0fb15SPaul Saab 		}
63a5f0fb15SPaul Saab 	} while (c != obrac || --n > 0);
64a5f0fb15SPaul Saab 
65a5f0fb15SPaul Saab 	/*
66a5f0fb15SPaul Saab 	 * Position the file just "after" the open bracket
67a5f0fb15SPaul Saab 	 * (in the direction in which we will be searching).
68a5f0fb15SPaul Saab 	 * If searching forward, we are already after the bracket.
69a5f0fb15SPaul Saab 	 * If searching backward, skip back over the open bracket.
70a5f0fb15SPaul Saab 	 */
71a5f0fb15SPaul Saab 	if (!forwdir)
72a5f0fb15SPaul Saab 		(void) ch_back_get();
73a5f0fb15SPaul Saab 
74a5f0fb15SPaul Saab 	/*
75a5f0fb15SPaul Saab 	 * Search the file for the matching bracket.
76a5f0fb15SPaul Saab 	 */
77a5f0fb15SPaul Saab 	chget = (forwdir) ? ch_forw_get : ch_back_get;
78a5f0fb15SPaul Saab 	nest = 0;
79a5f0fb15SPaul Saab 	while ((c = (*chget)()) != EOI)
80a5f0fb15SPaul Saab 	{
81a5f0fb15SPaul Saab 		if (c == obrac)
8295270f73SXin LI 		{
8395270f73SXin LI 			if (nest == INT_MAX)
8495270f73SXin LI 				break;
85a5f0fb15SPaul Saab 			nest++;
8695270f73SXin LI 		}
87a5f0fb15SPaul Saab 		else if (c == cbrac && --nest < 0)
88a5f0fb15SPaul Saab 		{
89a5f0fb15SPaul Saab 			/*
90a5f0fb15SPaul Saab 			 * Found the matching bracket.
91a5f0fb15SPaul Saab 			 * If searching backward, put it on the top line.
92a5f0fb15SPaul Saab 			 * If searching forward, put it on the bottom line.
93a5f0fb15SPaul Saab 			 */
94a5f0fb15SPaul Saab 			jump_line_loc(ch_tell(), forwdir ? -1 : 1);
95a5f0fb15SPaul Saab 			return;
96a5f0fb15SPaul Saab 		}
97a5f0fb15SPaul Saab 	}
98a5f0fb15SPaul Saab 	error("No matching bracket", NULL_PARG);
99a5f0fb15SPaul Saab }
100