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