Home | History | Annotate | Line # | Download | only in vi
v_match.c revision 1.3.8.2
      1 /*	$NetBSD: v_match.c,v 1.3.8.2 2014/08/19 23:51:53 tls Exp $ */
      2 /*-
      3  * Copyright (c) 1992, 1993, 1994
      4  *	The Regents of the University of California.  All rights reserved.
      5  * Copyright (c) 1992, 1993, 1994, 1995, 1996
      6  *	Keith Bostic.  All rights reserved.
      7  *
      8  * See the LICENSE file for redistribution information.
      9  */
     10 
     11 #include "config.h"
     12 
     13 #include <sys/cdefs.h>
     14 #if 0
     15 #ifndef lint
     16 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 ";
     17 #endif /* not lint */
     18 #else
     19 __RCSID("$NetBSD: v_match.c,v 1.3.8.2 2014/08/19 23:51:53 tls Exp $");
     20 #endif
     21 
     22 #include <sys/types.h>
     23 #include <sys/queue.h>
     24 #include <sys/time.h>
     25 
     26 #include <bitstring.h>
     27 #include <limits.h>
     28 #include <stdio.h>
     29 #include <string.h>
     30 
     31 #include "../common/common.h"
     32 #include "vi.h"
     33 
     34 /*
     35  * v_match -- %
     36  *	Search to matching character.
     37  *
     38  * PUBLIC: int v_match __P((SCR *, VICMD *));
     39  */
     40 int
     41 v_match(SCR *sp, VICMD *vp)
     42 {
     43 	VCS cs;
     44 	MARK *mp;
     45 	size_t cno, len, off;
     46 	int cnt, isempty, matchc, startc, (*gc)__P((SCR *, VCS *));
     47 	CHAR_T *p;
     48 	char *cp;
     49 	const char *match_chars;
     50 
     51 	static MARK match = { 0, 0 };
     52 	static int match_dir;
     53 
     54 	/*
     55 	 * Historically vi would match (), {} and [] however
     56 	 * an update included <>.  This is ok for editing HTML
     57 	 * but a pain in the butt for C source.
     58 	 * Making it an option lets the user decide what is 'right'.
     59 	 * Also fixed to do something sensible with "".
     60 	 */
     61 	match_chars = O_STR(sp, O_MATCHCHARS);
     62 
     63 	/*
     64 	 * !!!
     65 	 * Historic practice; ignore the count.
     66 	 *
     67 	 * !!!
     68 	 * Historical practice was to search for the initial character in the
     69 	 * forward direction only.
     70 	 */
     71 	if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) {
     72 		if (isempty)
     73 			goto nomatch;
     74 		return (1);
     75 	}
     76 	for (off = vp->m_start.cno;; ++off) {
     77 		if (off >= len) {
     78 nomatch:		msgq(sp, M_BERR, "184|No match character on this line");
     79 			return (1);
     80 		}
     81 		startc = p[off];
     82 		cp = strchr(match_chars, startc);
     83 		if (cp != NULL)
     84 			break;
     85 	}
     86 	cnt = cp - match_chars;
     87 	matchc = match_chars[cnt ^ 1];
     88 
     89 	/* Alternate back-forward search if startc and matchc the same */
     90 	if (startc == matchc) {
     91 		/* are we continuing from where last match finished? */
     92 		if (match.lno == vp->m_start.lno && match.cno ==vp->m_start.cno)
     93 			/* yes - continue in sequence */
     94 			match_dir++;
     95 		else
     96 			/* no - go forward, back, back, forward */
     97 			match_dir = 1;
     98 		if (match_dir & 2)
     99 			cnt++;
    100 	}
    101 	gc = cnt & 1 ? cs_prev : cs_next;
    102 
    103 	cs.cs_lno = vp->m_start.lno;
    104 	cs.cs_cno = off;
    105 	if (cs_init(sp, &cs))
    106 		return (1);
    107 	for (cnt = 1;;) {
    108 		if (gc(sp, &cs))
    109 			return (1);
    110 		if (cs.cs_flags != 0) {
    111 			if (cs.cs_flags == CS_EOF || cs.cs_flags == CS_SOF)
    112 				break;
    113 			continue;
    114 		}
    115 		if (cs.cs_ch == matchc && --cnt == 0)
    116 			break;
    117 		if (cs.cs_ch == startc)
    118 			++cnt;
    119 	}
    120 	if (cnt) {
    121 		msgq(sp, M_BERR, "185|Matching character not found");
    122 		return (1);
    123 	}
    124 
    125 	vp->m_stop.lno = cs.cs_lno;
    126 	vp->m_stop.cno = cs.cs_cno;
    127 
    128 	/*
    129 	 * If moving right, non-motion commands move to the end of the range.
    130 	 * Delete and yank stay at the start.
    131 	 *
    132 	 * If moving left, all commands move to the end of the range.
    133 	 *
    134 	 * !!!
    135 	 * Don't correct for leftward movement -- historic vi deleted the
    136 	 * starting cursor position when deleting to a match.
    137 	 */
    138 	if (vp->m_start.lno < vp->m_stop.lno ||
    139 	    (vp->m_start.lno == vp->m_stop.lno &&
    140 	    vp->m_start.cno < vp->m_stop.cno))
    141 		vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
    142 	else
    143 		vp->m_final = vp->m_stop;
    144 
    145 	match.lno = vp->m_final.lno;
    146 	match.cno = vp->m_final.cno;
    147 
    148 	/*
    149 	 * !!!
    150 	 * If the motion is across lines, and the earliest cursor position
    151 	 * is at or before any non-blank characters in the line, i.e. the
    152 	 * movement is cutting all of the line's text, and the later cursor
    153 	 * position has nothing other than whitespace characters between it
    154 	 * and the end of its line, the buffer is in line mode.
    155 	 */
    156 	if (!ISMOTION(vp) || vp->m_start.lno == vp->m_stop.lno)
    157 		return (0);
    158 	mp = vp->m_start.lno < vp->m_stop.lno ? &vp->m_start : &vp->m_stop;
    159 	if (mp->cno != 0) {
    160 		cno = 0;
    161 		if (nonblank(sp, mp->lno, &cno))
    162 			return (1);
    163 		if (cno < mp->cno)
    164 			return (0);
    165 	}
    166 	mp = vp->m_start.lno < vp->m_stop.lno ? &vp->m_stop : &vp->m_start;
    167 	if (db_get(sp, mp->lno, DBG_FATAL, &p, &len))
    168 		return (1);
    169 	for (p += mp->cno + 1, len -= mp->cno; --len; ++p)
    170 		if (!ISBLANK((UCHAR_T)*p))
    171 			return (0);
    172 	F_SET(vp, VM_LMODE);
    173 	return (0);
    174 }
    175