v_match.c revision 19304
119304Speter/*-
219304Speter * Copyright (c) 1992, 1993, 1994
319304Speter *	The Regents of the University of California.  All rights reserved.
419304Speter * Copyright (c) 1992, 1993, 1994, 1995, 1996
519304Speter *	Keith Bostic.  All rights reserved.
619304Speter *
719304Speter * See the LICENSE file for redistribution information.
819304Speter */
919304Speter
1019304Speter#include "config.h"
1119304Speter
1219304Speter#ifndef lint
1319304Speterstatic const char sccsid[] = "@(#)v_match.c	10.8 (Berkeley) 3/6/96";
1419304Speter#endif /* not lint */
1519304Speter
1619304Speter#include <sys/types.h>
1719304Speter#include <sys/queue.h>
1819304Speter#include <sys/time.h>
1919304Speter
2019304Speter#include <bitstring.h>
2119304Speter#include <limits.h>
2219304Speter#include <stdio.h>
2319304Speter#include <string.h>
2419304Speter
2519304Speter#include "../common/common.h"
2619304Speter#include "vi.h"
2719304Speter
2819304Speter/*
2919304Speter * v_match -- %
3019304Speter *	Search to matching character.
3119304Speter *
3219304Speter * PUBLIC: int v_match __P((SCR *, VICMD *));
3319304Speter */
3419304Speterint
3519304Speterv_match(sp, vp)
3619304Speter	SCR *sp;
3719304Speter	VICMD *vp;
3819304Speter{
3919304Speter	VCS cs;
4019304Speter	MARK *mp;
4119304Speter	size_t cno, len, off;
4219304Speter	int cnt, isempty, matchc, startc, (*gc)__P((SCR *, VCS *));
4319304Speter	char *p;
4419304Speter
4519304Speter	/*
4619304Speter	 * !!!
4719304Speter	 * Historic practice; ignore the count.
4819304Speter	 *
4919304Speter	 * !!!
5019304Speter	 * Historical practice was to search for the initial character in the
5119304Speter	 * forward direction only.
5219304Speter	 */
5319304Speter	if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) {
5419304Speter		if (isempty)
5519304Speter			goto nomatch;
5619304Speter		return (1);
5719304Speter	}
5819304Speter	for (off = vp->m_start.cno;; ++off) {
5919304Speter		if (off >= len) {
6019304Speternomatch:		msgq(sp, M_BERR, "184|No match character on this line");
6119304Speter			return (1);
6219304Speter		}
6319304Speter		switch (startc = p[off]) {
6419304Speter		case '(':
6519304Speter			matchc = ')';
6619304Speter			gc = cs_next;
6719304Speter			break;
6819304Speter		case ')':
6919304Speter			matchc = '(';
7019304Speter			gc = cs_prev;
7119304Speter			break;
7219304Speter		case '[':
7319304Speter			matchc = ']';
7419304Speter			gc = cs_next;
7519304Speter			break;
7619304Speter		case ']':
7719304Speter			matchc = '[';
7819304Speter			gc = cs_prev;
7919304Speter			break;
8019304Speter		case '{':
8119304Speter			matchc = '}';
8219304Speter			gc = cs_next;
8319304Speter			break;
8419304Speter		case '}':
8519304Speter			matchc = '{';
8619304Speter			gc = cs_prev;
8719304Speter			break;
8819304Speter		case '<':
8919304Speter			matchc = '>';
9019304Speter			gc = cs_next;
9119304Speter			break;
9219304Speter		case '>':
9319304Speter			matchc = '<';
9419304Speter			gc = cs_prev;
9519304Speter			break;
9619304Speter		default:
9719304Speter			continue;
9819304Speter		}
9919304Speter		break;
10019304Speter	}
10119304Speter
10219304Speter	cs.cs_lno = vp->m_start.lno;
10319304Speter	cs.cs_cno = off;
10419304Speter	if (cs_init(sp, &cs))
10519304Speter		return (1);
10619304Speter	for (cnt = 1;;) {
10719304Speter		if (gc(sp, &cs))
10819304Speter			return (1);
10919304Speter		if (cs.cs_flags != 0) {
11019304Speter			if (cs.cs_flags == CS_EOF || cs.cs_flags == CS_SOF)
11119304Speter				break;
11219304Speter			continue;
11319304Speter		}
11419304Speter		if (cs.cs_ch == startc)
11519304Speter			++cnt;
11619304Speter		else if (cs.cs_ch == matchc && --cnt == 0)
11719304Speter			break;
11819304Speter	}
11919304Speter	if (cnt) {
12019304Speter		msgq(sp, M_BERR, "185|Matching character not found");
12119304Speter		return (1);
12219304Speter	}
12319304Speter
12419304Speter	vp->m_stop.lno = cs.cs_lno;
12519304Speter	vp->m_stop.cno = cs.cs_cno;
12619304Speter
12719304Speter	/*
12819304Speter	 * If moving right, non-motion commands move to the end of the range.
12919304Speter	 * Delete and yank stay at the start.
13019304Speter	 *
13119304Speter	 * If moving left, all commands move to the end of the range.
13219304Speter	 *
13319304Speter	 * !!!
13419304Speter	 * Don't correct for leftward movement -- historic vi deleted the
13519304Speter	 * starting cursor position when deleting to a match.
13619304Speter	 */
13719304Speter	if (vp->m_start.lno < vp->m_stop.lno ||
13819304Speter	    vp->m_start.lno == vp->m_stop.lno &&
13919304Speter	    vp->m_start.cno < vp->m_stop.cno)
14019304Speter		vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
14119304Speter	else
14219304Speter		vp->m_final = vp->m_stop;
14319304Speter
14419304Speter	/*
14519304Speter	 * !!!
14619304Speter	 * If the motion is across lines, and the earliest cursor position
14719304Speter	 * is at or before any non-blank characters in the line, i.e. the
14819304Speter	 * movement is cutting all of the line's text, and the later cursor
14919304Speter	 * position has nothing other than whitespace characters between it
15019304Speter	 * and the end of its line, the buffer is in line mode.
15119304Speter	 */
15219304Speter	if (!ISMOTION(vp) || vp->m_start.lno == vp->m_stop.lno)
15319304Speter		return (0);
15419304Speter	mp = vp->m_start.lno < vp->m_stop.lno ? &vp->m_start : &vp->m_stop;
15519304Speter	if (mp->cno != 0) {
15619304Speter		cno = 0;
15719304Speter		if (nonblank(sp, mp->lno, &cno))
15819304Speter			return (1);
15919304Speter		if (cno < mp->cno)
16019304Speter			return (0);
16119304Speter	}
16219304Speter	mp = vp->m_start.lno < vp->m_stop.lno ? &vp->m_stop : &vp->m_start;
16319304Speter	if (db_get(sp, mp->lno, DBG_FATAL, &p, &len))
16419304Speter		return (1);
16519304Speter	for (p += mp->cno + 1, len -= mp->cno; --len; ++p)
16619304Speter		if (!isblank(*p))
16719304Speter			return (0);
16819304Speter	F_SET(vp, VM_LMODE);
16919304Speter	return (0);
17019304Speter}
171