Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / nvi / vi / v_match.c
blob697467ba038c459e2abbe5b591d5b7f1083314e7
1 /* $NetBSD: v_match.c,v 1.3 2008/12/05 22:51:43 christos Exp $ */
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.
9 * See the LICENSE file for redistribution information.
12 #include "config.h"
14 #ifndef lint
15 static const char sccsid[] = "Id: v_match.c,v 10.10 2001/06/25 15:19:32 skimo Exp (Berkeley) Date: 2001/06/25 15:19:32";
16 #endif /* not lint */
18 #include <sys/types.h>
19 #include <sys/queue.h>
20 #include <sys/time.h>
22 #include <bitstring.h>
23 #include <limits.h>
24 #include <stdio.h>
25 #include <string.h>
27 #include "../common/common.h"
28 #include "vi.h"
31 * v_match -- %
32 * Search to matching character.
34 * PUBLIC: int v_match __P((SCR *, VICMD *));
36 int
37 v_match(SCR *sp, VICMD *vp)
39 VCS cs;
40 MARK *mp;
41 size_t cno, len, off;
42 int cnt, isempty, matchc, startc, (*gc)__P((SCR *, VCS *));
43 CHAR_T *p;
44 char *cp;
45 const char *match_chars;
47 static MARK match = { 0, 0 };
48 static int match_dir;
51 * Historically vi would match (), {} and [] however
52 * an update included <>. This is ok for editing HTML
53 * but a pain in the butt for C source.
54 * Making it an option lets the user decide what is 'right'.
55 * Also fixed to do something sensible with "".
57 match_chars = O_STR(sp, O_MATCHCHARS);
60 * !!!
61 * Historic practice; ignore the count.
63 * !!!
64 * Historical practice was to search for the initial character in the
65 * forward direction only.
67 if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) {
68 if (isempty)
69 goto nomatch;
70 return (1);
72 for (off = vp->m_start.cno;; ++off) {
73 if (off >= len) {
74 nomatch: msgq(sp, M_BERR, "184|No match character on this line");
75 return (1);
77 startc = p[off];
78 cp = strchr(match_chars, startc);
79 if (cp != NULL)
80 break;
82 cnt = cp - match_chars;
83 matchc = match_chars[cnt ^ 1];
85 /* Alternate back-forward search if startc and matchc the same */
86 if (startc == matchc) {
87 /* are we continuing from where last match finished? */
88 if (match.lno == vp->m_start.lno && match.cno ==vp->m_start.cno)
89 /* yes - continue in sequence */
90 match_dir++;
91 else
92 /* no - go forward, back, back, forward */
93 match_dir = 1;
94 if (match_dir & 2)
95 cnt++;
97 gc = cnt & 1 ? cs_prev : cs_next;
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;
111 if (cs.cs_ch == matchc && --cnt == 0)
112 break;
113 if (cs.cs_ch == startc)
114 ++cnt;
116 if (cnt) {
117 msgq(sp, M_BERR, "185|Matching character not found");
118 return (1);
121 vp->m_stop.lno = cs.cs_lno;
122 vp->m_stop.cno = cs.cs_cno;
125 * If moving right, non-motion commands move to the end of the range.
126 * Delete and yank stay at the start.
128 * If moving left, all commands move to the end of the range.
130 * !!!
131 * Don't correct for leftward movement -- historic vi deleted the
132 * starting cursor position when deleting to a match.
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;
141 match.lno = vp->m_final.lno;
142 match.cno = vp->m_final.cno;
145 * !!!
146 * If the motion is across lines, and the earliest cursor position
147 * is at or before any non-blank characters in the line, i.e. the
148 * movement is cutting all of the line's text, and the later cursor
149 * position has nothing other than whitespace characters between it
150 * and the end of its line, the buffer is in line mode.
152 if (!ISMOTION(vp) || vp->m_start.lno == vp->m_stop.lno)
153 return (0);
154 mp = vp->m_start.lno < vp->m_stop.lno ? &vp->m_start : &vp->m_stop;
155 if (mp->cno != 0) {
156 cno = 0;
157 if (nonblank(sp, mp->lno, &cno))
158 return (1);
159 if (cno < mp->cno)
160 return (0);
162 mp = vp->m_start.lno < vp->m_stop.lno ? &vp->m_stop : &vp->m_start;
163 if (db_get(sp, mp->lno, DBG_FATAL, &p, &len))
164 return (1);
165 for (p += mp->cno + 1, len -= mp->cno; --len; ++p)
166 if (!isblank(*p))
167 return (0);
168 F_SET(vp, VM_LMODE);
169 return (0);