GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/vi/build/../vi/v_match.c Lines: 0 60 0.0 %
Date: 2017-11-13 Branches: 0 61 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: v_match.c,v 1.9 2016/01/06 22:28:52 millert Exp $	*/
2
3
/*-
4
 * Copyright (c) 1992, 1993, 1994
5
 *	The Regents of the University of California.  All rights reserved.
6
 * Copyright (c) 1992, 1993, 1994, 1995, 1996
7
 *	Keith Bostic.  All rights reserved.
8
 *
9
 * See the LICENSE file for redistribution information.
10
 */
11
12
#include "config.h"
13
14
#include <sys/types.h>
15
#include <sys/queue.h>
16
#include <sys/time.h>
17
18
#include <bitstring.h>
19
#include <ctype.h>
20
#include <limits.h>
21
#include <stdio.h>
22
#include <string.h>
23
24
#include "../common/common.h"
25
#include "vi.h"
26
27
/*
28
 * v_match -- %
29
 *	Search to matching character.
30
 *
31
 * PUBLIC: int v_match(SCR *, VICMD *);
32
 */
33
int
34
v_match(SCR *sp, VICMD *vp)
35
{
36
	VCS cs;
37
	MARK *mp;
38
	size_t cno, len, off;
39
	int cnt, isempty, matchc, startc, (*gc)(SCR *, VCS *);
40
	char *p;
41
42
	/*
43
	 * !!!
44
	 * Historic practice; ignore the count.
45
	 *
46
	 * !!!
47
	 * Historical practice was to search for the initial character in the
48
	 * forward direction only.
49
	 */
50
	if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) {
51
		if (isempty)
52
			goto nomatch;
53
		return (1);
54
	}
55
	for (off = vp->m_start.cno;; ++off) {
56
		if (off >= len) {
57
nomatch:		msgq(sp, M_BERR, "No match character on this line");
58
			return (1);
59
		}
60
		switch (startc = p[off]) {
61
		case '(':
62
			matchc = ')';
63
			gc = cs_next;
64
			break;
65
		case ')':
66
			matchc = '(';
67
			gc = cs_prev;
68
			break;
69
		case '[':
70
			matchc = ']';
71
			gc = cs_next;
72
			break;
73
		case ']':
74
			matchc = '[';
75
			gc = cs_prev;
76
			break;
77
		case '{':
78
			matchc = '}';
79
			gc = cs_next;
80
			break;
81
		case '}':
82
			matchc = '{';
83
			gc = cs_prev;
84
			break;
85
		case '<':
86
			matchc = '>';
87
			gc = cs_next;
88
			break;
89
		case '>':
90
			matchc = '<';
91
			gc = cs_prev;
92
			break;
93
		default:
94
			continue;
95
		}
96
		break;
97
	}
98
99
	cs.cs_lno = vp->m_start.lno;
100
	cs.cs_cno = off;
101
	if (cs_init(sp, &cs))
102
		return (1);
103
	for (cnt = 1;;) {
104
		if (gc(sp, &cs))
105
			return (1);
106
		if (cs.cs_flags != 0) {
107
			if (cs.cs_flags == CS_EOF || cs.cs_flags == CS_SOF)
108
				break;
109
			continue;
110
		}
111
		if (cs.cs_ch == startc)
112
			++cnt;
113
		else if (cs.cs_ch == matchc && --cnt == 0)
114
			break;
115
	}
116
	if (cnt) {
117
		msgq(sp, M_BERR, "Matching character not found");
118
		return (1);
119
	}
120
121
	vp->m_stop.lno = cs.cs_lno;
122
	vp->m_stop.cno = cs.cs_cno;
123
124
	/*
125
	 * If moving right, non-motion commands move to the end of the range.
126
	 * Delete and yank stay at the start.
127
	 *
128
	 * If moving left, all commands move to the end of the range.
129
	 *
130
	 * !!!
131
	 * Don't correct for leftward movement -- historic vi deleted the
132
	 * starting cursor position when deleting to a match.
133
	 */
134
	if (vp->m_start.lno < vp->m_stop.lno ||
135
	    (vp->m_start.lno == vp->m_stop.lno &&
136
	    vp->m_start.cno < vp->m_stop.cno))
137
		vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
138
	else
139
		vp->m_final = vp->m_stop;
140
141
	/*
142
	 * !!!
143
	 * If the motion is across lines, and the earliest cursor position
144
	 * is at or before any non-blank characters in the line, i.e. the
145
	 * movement is cutting all of the line's text, and the later cursor
146
	 * position has nothing other than whitespace characters between it
147
	 * and the end of its line, the buffer is in line mode.
148
	 */
149
	if (!ISMOTION(vp) || vp->m_start.lno == vp->m_stop.lno)
150
		return (0);
151
	mp = vp->m_start.lno < vp->m_stop.lno ? &vp->m_start : &vp->m_stop;
152
	if (mp->cno != 0) {
153
		cno = 0;
154
		if (nonblank(sp, mp->lno, &cno))
155
			return (1);
156
		if (cno < mp->cno)
157
			return (0);
158
	}
159
	mp = vp->m_start.lno < vp->m_stop.lno ? &vp->m_stop : &vp->m_start;
160
	if (db_get(sp, mp->lno, DBG_FATAL, &p, &len))
161
		return (1);
162
	for (p += mp->cno + 1, len -= mp->cno; --len; ++p)
163
		if (!isblank(*p))
164
			return (0);
165
	F_SET(vp, VM_LMODE);
166
	return (0);
167
}