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 13254225Speterstatic const char sccsid[] = "$Id: v_match.c,v 10.11 2012/02/11 00:33:46 zy Exp $"; 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> 21254225Speter#include <ctype.h> 2219304Speter#include <limits.h> 2319304Speter#include <stdio.h> 24254225Speter#include <stdlib.h> 2519304Speter#include <string.h> 2619304Speter 2719304Speter#include "../common/common.h" 2819304Speter#include "vi.h" 2919304Speter 3019304Speter/* 3119304Speter * v_match -- % 3219304Speter * Search to matching character. 3319304Speter * 34281373Sbapt * PUBLIC: int v_match(SCR *, VICMD *); 3519304Speter */ 3619304Speterint 37254225Speterv_match(SCR *sp, VICMD *vp) 3819304Speter{ 3919304Speter VCS cs; 4019304Speter MARK *mp; 4119304Speter size_t cno, len, off; 42281373Sbapt int cnt, isempty, matchc, startc, (*gc)(SCR *, VCS *); 43254225Speter CHAR_T *p; 44254225Speter CHAR_T *cp; 45254225Speter const CHAR_T *match_chars; 4619304Speter 4719304Speter /* 48254225Speter * Historically vi would match (), {} and [] however 49254225Speter * an update included <>. This is ok for editing HTML 50254225Speter * but a pain in the butt for C source. 51254225Speter * Making it an option lets the user decide what is 'right'. 52254225Speter */ 53254225Speter match_chars = VIP(sp)->mcs; 54254225Speter 55254225Speter /* 5619304Speter * !!! 5719304Speter * Historic practice; ignore the count. 5819304Speter * 5919304Speter * !!! 6019304Speter * Historical practice was to search for the initial character in the 6119304Speter * forward direction only. 6219304Speter */ 6319304Speter if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) { 6419304Speter if (isempty) 6519304Speter goto nomatch; 6619304Speter return (1); 6719304Speter } 6819304Speter for (off = vp->m_start.cno;; ++off) { 6919304Speter if (off >= len) { 7019304Speternomatch: msgq(sp, M_BERR, "184|No match character on this line"); 7119304Speter return (1); 7219304Speter } 73254225Speter startc = p[off]; 74254225Speter cp = STRCHR(match_chars, startc); 75254225Speter if (cp != NULL) { 76254225Speter cnt = cp - match_chars; 77254225Speter matchc = match_chars[cnt ^ 1]; 78254225Speter gc = cnt & 1 ? cs_prev : cs_next; 7919304Speter break; 8019304Speter } 8119304Speter } 8219304Speter 8319304Speter cs.cs_lno = vp->m_start.lno; 8419304Speter cs.cs_cno = off; 8519304Speter if (cs_init(sp, &cs)) 8619304Speter return (1); 8719304Speter for (cnt = 1;;) { 8819304Speter if (gc(sp, &cs)) 8919304Speter return (1); 9019304Speter if (cs.cs_flags != 0) { 9119304Speter if (cs.cs_flags == CS_EOF || cs.cs_flags == CS_SOF) 9219304Speter break; 9319304Speter continue; 9419304Speter } 9519304Speter if (cs.cs_ch == startc) 9619304Speter ++cnt; 9719304Speter else if (cs.cs_ch == matchc && --cnt == 0) 9819304Speter break; 9919304Speter } 10019304Speter if (cnt) { 10119304Speter msgq(sp, M_BERR, "185|Matching character not found"); 10219304Speter return (1); 10319304Speter } 10419304Speter 10519304Speter vp->m_stop.lno = cs.cs_lno; 10619304Speter vp->m_stop.cno = cs.cs_cno; 10719304Speter 10819304Speter /* 10919304Speter * If moving right, non-motion commands move to the end of the range. 11019304Speter * Delete and yank stay at the start. 11119304Speter * 11219304Speter * If moving left, all commands move to the end of the range. 11319304Speter * 11419304Speter * !!! 11519304Speter * Don't correct for leftward movement -- historic vi deleted the 11619304Speter * starting cursor position when deleting to a match. 11719304Speter */ 11819304Speter if (vp->m_start.lno < vp->m_stop.lno || 119254225Speter (vp->m_start.lno == vp->m_stop.lno && 120254225Speter vp->m_start.cno < vp->m_stop.cno)) 12119304Speter vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop; 12219304Speter else 12319304Speter vp->m_final = vp->m_stop; 12419304Speter 12519304Speter /* 12619304Speter * !!! 12719304Speter * If the motion is across lines, and the earliest cursor position 12819304Speter * is at or before any non-blank characters in the line, i.e. the 12919304Speter * movement is cutting all of the line's text, and the later cursor 13019304Speter * position has nothing other than whitespace characters between it 13119304Speter * and the end of its line, the buffer is in line mode. 13219304Speter */ 13319304Speter if (!ISMOTION(vp) || vp->m_start.lno == vp->m_stop.lno) 13419304Speter return (0); 13519304Speter mp = vp->m_start.lno < vp->m_stop.lno ? &vp->m_start : &vp->m_stop; 13619304Speter if (mp->cno != 0) { 13719304Speter cno = 0; 13819304Speter if (nonblank(sp, mp->lno, &cno)) 13919304Speter return (1); 14019304Speter if (cno < mp->cno) 14119304Speter return (0); 14219304Speter } 14319304Speter mp = vp->m_start.lno < vp->m_stop.lno ? &vp->m_stop : &vp->m_start; 14419304Speter if (db_get(sp, mp->lno, DBG_FATAL, &p, &len)) 14519304Speter return (1); 14619304Speter for (p += mp->cno + 1, len -= mp->cno; --len; ++p) 14719304Speter if (!isblank(*p)) 14819304Speter return (0); 14919304Speter F_SET(vp, VM_LMODE); 15019304Speter return (0); 15119304Speter} 152254225Speter 153254225Speter/* 154254225Speter * v_buildmcs -- 155254225Speter * Build the match character list. 156254225Speter * 157281373Sbapt * PUBLIC: int v_buildmcs(SCR *, char *); 158254225Speter */ 159254225Speterint 160254225Speterv_buildmcs(SCR *sp, char *str) 161254225Speter{ 162254225Speter CHAR_T **mp = &VIP(sp)->mcs; 163254225Speter size_t len = strlen(str) + 1; 164254225Speter 165254225Speter if (*mp != NULL) 166254225Speter free(*mp); 167254225Speter MALLOC(sp, *mp, CHAR_T *, len * sizeof(CHAR_T)); 168254225Speter if (*mp == NULL) 169254225Speter return (1); 170254225Speter#ifdef USE_WIDECHAR 171254225Speter if (mbstowcs(*mp, str, len) == (size_t)-1) 172254225Speter return (1); 173254225Speter#else 174254225Speter memcpy(*mp, str, len); 175254225Speter#endif 176254225Speter return (0); 177254225Speter} 178