v_match.c revision 19304
1243750Srwatson/*-
2156283Srwatson * Copyright (c) 1992, 1993, 1994
3156283Srwatson *	The Regents of the University of California.  All rights reserved.
4243750Srwatson * Copyright (c) 1992, 1993, 1994, 1995, 1996
5243750Srwatson *	Keith Bostic.  All rights reserved.
6156283Srwatson *
7156283Srwatson * See the LICENSE file for redistribution information.
8156283Srwatson */
9156283Srwatson
10156283Srwatson#include "config.h"
11156283Srwatson
12156283Srwatson#ifndef lint
13156283Srwatsonstatic const char sccsid[] = "@(#)v_match.c	10.8 (Berkeley) 3/6/96";
14156283Srwatson#endif /* not lint */
15156283Srwatson
16156283Srwatson#include <sys/types.h>
17156283Srwatson#include <sys/queue.h>
18243750Srwatson#include <sys/time.h>
19243750Srwatson
20243750Srwatson#include <bitstring.h>
21243750Srwatson#include <limits.h>
22243750Srwatson#include <stdio.h>
23243750Srwatson#include <string.h>
24243750Srwatson
25243750Srwatson#include "../common/common.h"
26243750Srwatson#include "vi.h"
27243750Srwatson
28243750Srwatson/*
29243750Srwatson * v_match -- %
30243750Srwatson *	Search to matching character.
31243750Srwatson *
32243750Srwatson * PUBLIC: int v_match __P((SCR *, VICMD *));
33243750Srwatson */
34243750Srwatsonint
35156283Srwatsonv_match(sp, vp)
36243750Srwatson	SCR *sp;
37156283Srwatson	VICMD *vp;
38243750Srwatson{
39156283Srwatson	VCS cs;
40156283Srwatson	MARK *mp;
41156283Srwatson	size_t cno, len, off;
42156283Srwatson	int cnt, isempty, matchc, startc, (*gc)__P((SCR *, VCS *));
43156283Srwatson	char *p;
44156283Srwatson
45156283Srwatson	/*
46156283Srwatson	 * !!!
47156283Srwatson	 * Historic practice; ignore the count.
48156283Srwatson	 *
49156283Srwatson	 * !!!
50156283Srwatson	 * Historical practice was to search for the initial character in the
51156283Srwatson	 * forward direction only.
52156283Srwatson	 */
53156283Srwatson	if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) {
54156283Srwatson		if (isempty)
55156283Srwatson			goto nomatch;
56156283Srwatson		return (1);
57156283Srwatson	}
58156283Srwatson	for (off = vp->m_start.cno;; ++off) {
59156283Srwatson		if (off >= len) {
60156283Srwatsonnomatch:		msgq(sp, M_BERR, "184|No match character on this line");
61156283Srwatson			return (1);
62156283Srwatson		}
63243750Srwatson		switch (startc = p[off]) {
64156283Srwatson		case '(':
65156283Srwatson			matchc = ')';
66243750Srwatson			gc = cs_next;
67243750Srwatson			break;
68243750Srwatson		case ')':
69243750Srwatson			matchc = '(';
70243750Srwatson			gc = cs_prev;
71156283Srwatson			break;
72156283Srwatson		case '[':
73156283Srwatson			matchc = ']';
74156283Srwatson			gc = cs_next;
75156283Srwatson			break;
76243750Srwatson		case ']':
77243750Srwatson			matchc = '[';
78243750Srwatson			gc = cs_prev;
79243750Srwatson			break;
80243750Srwatson		case '{':
81243750Srwatson			matchc = '}';
82243750Srwatson			gc = cs_next;
83243750Srwatson			break;
84243750Srwatson		case '}':
85243750Srwatson			matchc = '{';
86243750Srwatson			gc = cs_prev;
87243750Srwatson			break;
88243750Srwatson		case '<':
89243750Srwatson			matchc = '>';
90243750Srwatson			gc = cs_next;
91243750Srwatson			break;
92243750Srwatson		case '>':
93243750Srwatson			matchc = '<';
94243750Srwatson			gc = cs_prev;
95243750Srwatson			break;
96243750Srwatson		default:
97243750Srwatson			continue;
98156283Srwatson		}
99156283Srwatson		break;
100156283Srwatson	}
101156283Srwatson
102156283Srwatson	cs.cs_lno = vp->m_start.lno;
103156283Srwatson	cs.cs_cno = off;
104156283Srwatson	if (cs_init(sp, &cs))
105156283Srwatson		return (1);
106156283Srwatson	for (cnt = 1;;) {
107156283Srwatson		if (gc(sp, &cs))
108156283Srwatson			return (1);
109156283Srwatson		if (cs.cs_flags != 0) {
110156283Srwatson			if (cs.cs_flags == CS_EOF || cs.cs_flags == CS_SOF)
111156283Srwatson				break;
112156283Srwatson			continue;
113156283Srwatson		}
114156283Srwatson		if (cs.cs_ch == startc)
115156283Srwatson			++cnt;
116156283Srwatson		else if (cs.cs_ch == matchc && --cnt == 0)
117156283Srwatson			break;
118243750Srwatson	}
119191273Srwatson	if (cnt) {
120243750Srwatson		msgq(sp, M_BERR, "185|Matching character not found");
121156283Srwatson		return (1);
122156283Srwatson	}
123156283Srwatson
124156283Srwatson	vp->m_stop.lno = cs.cs_lno;
125156283Srwatson	vp->m_stop.cno = cs.cs_cno;
126243750Srwatson
127173143Srwatson	/*
128173143Srwatson	 * If moving right, non-motion commands move to the end of the range.
129156283Srwatson	 * Delete and yank stay at the start.
130156283Srwatson	 *
131156283Srwatson	 * If moving left, all commands move to the end of the range.
132156283Srwatson	 *
133243750Srwatson	 * !!!
134156283Srwatson	 * Don't correct for leftward movement -- historic vi deleted the
135243750Srwatson	 * starting cursor position when deleting to a match.
136243750Srwatson	 */
137243750Srwatson	if (vp->m_start.lno < vp->m_stop.lno ||
138156283Srwatson	    vp->m_start.lno == vp->m_stop.lno &&
139156283Srwatson	    vp->m_start.cno < vp->m_stop.cno)
140156283Srwatson		vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
141243750Srwatson	else
142156283Srwatson		vp->m_final = vp->m_stop;
143156283Srwatson
144156283Srwatson	/*
145156283Srwatson	 * !!!
146243750Srwatson	 * If the motion is across lines, and the earliest cursor position
147185573Srwatson	 * is at or before any non-blank characters in the line, i.e. the
148173143Srwatson	 * movement is cutting all of the line's text, and the later cursor
149243750Srwatson	 * position has nothing other than whitespace characters between it
150191273Srwatson	 * and the end of its line, the buffer is in line mode.
151243750Srwatson	 */
152156283Srwatson	if (!ISMOTION(vp) || vp->m_start.lno == vp->m_stop.lno)
153243750Srwatson		return (0);
154243750Srwatson	mp = vp->m_start.lno < vp->m_stop.lno ? &vp->m_start : &vp->m_stop;
155156283Srwatson	if (mp->cno != 0) {
156156283Srwatson		cno = 0;
157156283Srwatson		if (nonblank(sp, mp->lno, &cno))
158156283Srwatson			return (1);
159156283Srwatson		if (cno < mp->cno)
160243750Srwatson			return (0);
161156283Srwatson	}
162156283Srwatson	mp = vp->m_start.lno < vp->m_stop.lno ? &vp->m_stop : &vp->m_start;
163156283Srwatson	if (db_get(sp, mp->lno, DBG_FATAL, &p, &len))
164173143Srwatson		return (1);
165156283Srwatson	for (p += mp->cno + 1, len -= mp->cno; --len; ++p)
166156283Srwatson		if (!isblank(*p))
167156283Srwatson			return (0);
168156283Srwatson	F_SET(vp, VM_LMODE);
169243750Srwatson	return (0);
170243750Srwatson}
171173143Srwatson