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_ch.c,v 10.11 2011/12/02 19:49:50 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> 2119304Speter#include <limits.h> 2219304Speter#include <stdio.h> 2319304Speter#include <stdlib.h> 2419304Speter 2519304Speter#include "../common/common.h" 2619304Speter#include "vi.h" 2719304Speter 28281373Sbaptstatic void notfound(SCR *, ARG_CHAR_T); 29281373Sbaptstatic void noprev(SCR *); 3019304Speter 3119304Speter/* 3219304Speter * v_chrepeat -- [count]; 3319304Speter * Repeat the last F, f, T or t search. 3419304Speter * 35281373Sbapt * PUBLIC: int v_chrepeat(SCR *, VICMD *); 3619304Speter */ 3719304Speterint 38254225Speterv_chrepeat(SCR *sp, VICMD *vp) 3919304Speter{ 4019304Speter vp->character = VIP(sp)->lastckey; 4119304Speter 4219304Speter switch (VIP(sp)->csearchdir) { 4319304Speter case CNOTSET: 4419304Speter noprev(sp); 4519304Speter return (1); 4619304Speter case FSEARCH: 4719304Speter return (v_chF(sp, vp)); 4819304Speter case fSEARCH: 4919304Speter return (v_chf(sp, vp)); 5019304Speter case TSEARCH: 5119304Speter return (v_chT(sp, vp)); 5219304Speter case tSEARCH: 5319304Speter return (v_cht(sp, vp)); 5419304Speter default: 5519304Speter abort(); 5619304Speter } 5719304Speter /* NOTREACHED */ 5819304Speter} 5919304Speter 6019304Speter/* 6119304Speter * v_chrrepeat -- [count], 6219304Speter * Repeat the last F, f, T or t search in the reverse direction. 6319304Speter * 64281373Sbapt * PUBLIC: int v_chrrepeat(SCR *, VICMD *); 6519304Speter */ 6619304Speterint 67254225Speterv_chrrepeat(SCR *sp, VICMD *vp) 6819304Speter{ 6919304Speter cdir_t savedir; 7019304Speter int rval; 7119304Speter 7219304Speter vp->character = VIP(sp)->lastckey; 7319304Speter savedir = VIP(sp)->csearchdir; 7419304Speter 7519304Speter switch (VIP(sp)->csearchdir) { 7619304Speter case CNOTSET: 7719304Speter noprev(sp); 7819304Speter return (1); 7919304Speter case FSEARCH: 8019304Speter rval = v_chf(sp, vp); 8119304Speter break; 8219304Speter case fSEARCH: 8319304Speter rval = v_chF(sp, vp); 8419304Speter break; 8519304Speter case TSEARCH: 8619304Speter rval = v_cht(sp, vp); 8719304Speter break; 8819304Speter case tSEARCH: 8919304Speter rval = v_chT(sp, vp); 9019304Speter break; 9119304Speter default: 9219304Speter abort(); 9319304Speter } 9419304Speter VIP(sp)->csearchdir = savedir; 9519304Speter return (rval); 9619304Speter} 9719304Speter 9819304Speter/* 9919304Speter * v_cht -- [count]tc 10019304Speter * Search forward in the line for the character before the next 10119304Speter * occurrence of the specified character. 10219304Speter * 103281373Sbapt * PUBLIC: int v_cht(SCR *, VICMD *); 10419304Speter */ 10519304Speterint 106254225Speterv_cht(SCR *sp, VICMD *vp) 10719304Speter{ 10819304Speter if (v_chf(sp, vp)) 10919304Speter return (1); 11019304Speter 11119304Speter /* 11219304Speter * v_chf places the cursor on the character, where the 't' 11319304Speter * command wants it to its left. We know this is safe since 11419304Speter * we had to move right for v_chf() to have succeeded. 11519304Speter */ 11619304Speter --vp->m_stop.cno; 11719304Speter 11819304Speter /* 11919304Speter * Make any necessary correction to the motion decision made 12019304Speter * by the v_chf routine. 12119304Speter */ 12219304Speter if (!ISMOTION(vp)) 12319304Speter vp->m_final = vp->m_stop; 12419304Speter 12519304Speter VIP(sp)->csearchdir = tSEARCH; 12619304Speter return (0); 12719304Speter} 12819304Speter 12919304Speter/* 13019304Speter * v_chf -- [count]fc 13119304Speter * Search forward in the line for the next occurrence of the 13219304Speter * specified character. 13319304Speter * 134281373Sbapt * PUBLIC: int v_chf(SCR *, VICMD *); 13519304Speter */ 13619304Speterint 137254225Speterv_chf(SCR *sp, VICMD *vp) 13819304Speter{ 13919304Speter size_t len; 14019304Speter u_long cnt; 141254225Speter int isempty; 142254225Speter ARG_CHAR_T key; 143254225Speter CHAR_T *endp, *p, *startp; 14419304Speter 14519304Speter /* 14619304Speter * !!! 14719304Speter * If it's a dot command, it doesn't reset the key for which we're 14819304Speter * searching, e.g. in "df1|f2|.|;", the ';' searches for a '2'. 14919304Speter */ 15019304Speter key = vp->character; 15119304Speter if (!F_ISSET(vp, VC_ISDOT)) 15219304Speter VIP(sp)->lastckey = key; 15319304Speter VIP(sp)->csearchdir = fSEARCH; 15419304Speter 15519304Speter if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) { 15619304Speter if (isempty) 15719304Speter goto empty; 15819304Speter return (1); 15919304Speter } 16019304Speter 16119304Speter if (len == 0) { 16219304Speterempty: notfound(sp, key); 16319304Speter return (1); 16419304Speter } 16519304Speter 16619304Speter endp = (startp = p) + len; 16719304Speter p += vp->m_start.cno; 16819304Speter for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) { 16919304Speter while (++p < endp && *p != key); 17019304Speter if (p == endp) { 17119304Speter notfound(sp, key); 17219304Speter return (1); 17319304Speter } 17419304Speter } 17519304Speter 17619304Speter vp->m_stop.cno = p - startp; 17719304Speter 17819304Speter /* 17919304Speter * Non-motion commands move to the end of the range. 18019304Speter * Delete and yank stay at the start, ignore others. 18119304Speter */ 18219304Speter vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop; 18319304Speter return (0); 18419304Speter} 18519304Speter 18619304Speter/* 18719304Speter * v_chT -- [count]Tc 18819304Speter * Search backward in the line for the character after the next 18919304Speter * occurrence of the specified character. 19019304Speter * 191281373Sbapt * PUBLIC: int v_chT(SCR *, VICMD *); 19219304Speter */ 19319304Speterint 194254225Speterv_chT(SCR *sp, VICMD *vp) 19519304Speter{ 19619304Speter if (v_chF(sp, vp)) 19719304Speter return (1); 19819304Speter 19919304Speter /* 20019304Speter * v_chF places the cursor on the character, where the 'T' 20119304Speter * command wants it to its right. We know this is safe since 20219304Speter * we had to move left for v_chF() to have succeeded. 20319304Speter */ 20419304Speter ++vp->m_stop.cno; 20519304Speter vp->m_final = vp->m_stop; 20619304Speter 20719304Speter VIP(sp)->csearchdir = TSEARCH; 20819304Speter return (0); 20919304Speter} 21019304Speter 21119304Speter/* 21219304Speter * v_chF -- [count]Fc 21319304Speter * Search backward in the line for the next occurrence of the 21419304Speter * specified character. 21519304Speter * 216281373Sbapt * PUBLIC: int v_chF(SCR *, VICMD *); 21719304Speter */ 21819304Speterint 219254225Speterv_chF(SCR *sp, VICMD *vp) 22019304Speter{ 22119304Speter size_t len; 22219304Speter u_long cnt; 223254225Speter int isempty; 224254225Speter ARG_CHAR_T key; 225254225Speter CHAR_T *endp, *p; 22619304Speter 22719304Speter /* 22819304Speter * !!! 22919304Speter * If it's a dot command, it doesn't reset the key for which 23019304Speter * we're searching, e.g. in "df1|f2|.|;", the ';' searches 23119304Speter * for a '2'. 23219304Speter */ 23319304Speter key = vp->character; 23419304Speter if (!F_ISSET(vp, VC_ISDOT)) 23519304Speter VIP(sp)->lastckey = key; 23619304Speter VIP(sp)->csearchdir = FSEARCH; 23719304Speter 23819304Speter if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) { 23919304Speter if (isempty) 24019304Speter goto empty; 24119304Speter return (1); 24219304Speter } 24319304Speter 24419304Speter if (len == 0) { 24519304Speterempty: notfound(sp, key); 24619304Speter return (1); 24719304Speter } 24819304Speter 24919304Speter endp = p - 1; 25019304Speter p += vp->m_start.cno; 25119304Speter for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) { 25219304Speter while (--p > endp && *p != key); 25319304Speter if (p == endp) { 25419304Speter notfound(sp, key); 25519304Speter return (1); 25619304Speter } 25719304Speter } 25819304Speter 25919304Speter vp->m_stop.cno = (p - endp) - 1; 26019304Speter 26119304Speter /* 26219304Speter * All commands move to the end of the range. Motion commands 26319304Speter * adjust the starting point to the character before the current 26419304Speter * one. 26519304Speter */ 26619304Speter vp->m_final = vp->m_stop; 26719304Speter if (ISMOTION(vp)) 26819304Speter --vp->m_start.cno; 26919304Speter return (0); 27019304Speter} 27119304Speter 27219304Speterstatic void 273254225Speternoprev(SCR *sp) 27419304Speter{ 27519304Speter msgq(sp, M_BERR, "178|No previous F, f, T or t search"); 27619304Speter} 27719304Speter 27819304Speterstatic void 279254225Speternotfound(SCR *sp, ARG_CHAR_T ch) 28019304Speter{ 28119304Speter msgq(sp, M_BERR, "179|%s not found", KEY_NAME(sp, ch)); 28219304Speter} 283