Home | History | Annotate | Line # | Download | only in vi
      1 /*	$NetBSD: v_ch.c,v 1.3 2014/01/26 21:43:45 christos 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_ch.c,v 10.10 2001/06/25 15:19:30 skimo Exp  (Berkeley) Date: 2001/06/25 15:19:30 ";
     17 #endif /* not lint */
     18 #else
     19 __RCSID("$NetBSD: v_ch.c,v 1.3 2014/01/26 21:43:45 christos 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 <stdlib.h>
     30 
     31 #include "../common/common.h"
     32 #include "vi.h"
     33 
     34 static void notfound __P((SCR *, ARG_CHAR_T));
     35 static void noprev __P((SCR *));
     36 
     37 /*
     38  * v_chrepeat -- [count];
     39  *	Repeat the last F, f, T or t search.
     40  *
     41  * PUBLIC: int v_chrepeat __P((SCR *, VICMD *));
     42  */
     43 int
     44 v_chrepeat(SCR *sp, VICMD *vp)
     45 {
     46 	vp->character = VIP(sp)->lastckey;
     47 
     48 	switch (VIP(sp)->csearchdir) {
     49 	case CNOTSET:
     50 		noprev(sp);
     51 		return (1);
     52 	case FSEARCH:
     53 		return (v_chF(sp, vp));
     54 	case fSEARCH:
     55 		return (v_chf(sp, vp));
     56 	case TSEARCH:
     57 		return (v_chT(sp, vp));
     58 	case tSEARCH:
     59 		return (v_cht(sp, vp));
     60 	default:
     61 		abort();
     62 	}
     63 	/* NOTREACHED */
     64 }
     65 
     66 /*
     67  * v_chrrepeat -- [count],
     68  *	Repeat the last F, f, T or t search in the reverse direction.
     69  *
     70  * PUBLIC: int v_chrrepeat __P((SCR *, VICMD *));
     71  */
     72 int
     73 v_chrrepeat(SCR *sp, VICMD *vp)
     74 {
     75 	cdir_t savedir;
     76 	int rval;
     77 
     78 	vp->character = VIP(sp)->lastckey;
     79 	savedir = VIP(sp)->csearchdir;
     80 
     81 	switch (VIP(sp)->csearchdir) {
     82 	case CNOTSET:
     83 		noprev(sp);
     84 		return (1);
     85 	case FSEARCH:
     86 		rval = v_chf(sp, vp);
     87 		break;
     88 	case fSEARCH:
     89 		rval = v_chF(sp, vp);
     90 		break;
     91 	case TSEARCH:
     92 		rval = v_cht(sp, vp);
     93 		break;
     94 	case tSEARCH:
     95 		rval = v_chT(sp, vp);
     96 		break;
     97 	default:
     98 		abort();
     99 	}
    100 	VIP(sp)->csearchdir = savedir;
    101 	return (rval);
    102 }
    103 
    104 /*
    105  * v_cht -- [count]tc
    106  *	Search forward in the line for the character before the next
    107  *	occurrence of the specified character.
    108  *
    109  * PUBLIC: int v_cht __P((SCR *, VICMD *));
    110  */
    111 int
    112 v_cht(SCR *sp, VICMD *vp)
    113 {
    114 	if (v_chf(sp, vp))
    115 		return (1);
    116 
    117 	/*
    118 	 * v_chf places the cursor on the character, where the 't'
    119 	 * command wants it to its left.  We know this is safe since
    120 	 * we had to move right for v_chf() to have succeeded.
    121 	 */
    122 	--vp->m_stop.cno;
    123 
    124 	/*
    125 	 * Make any necessary correction to the motion decision made
    126 	 * by the v_chf routine.
    127 	 */
    128 	if (!ISMOTION(vp))
    129 		vp->m_final = vp->m_stop;
    130 
    131 	VIP(sp)->csearchdir = tSEARCH;
    132 	return (0);
    133 }
    134 
    135 /*
    136  * v_chf -- [count]fc
    137  *	Search forward in the line for the next occurrence of the
    138  *	specified character.
    139  *
    140  * PUBLIC: int v_chf __P((SCR *, VICMD *));
    141  */
    142 int
    143 v_chf(SCR *sp, VICMD *vp)
    144 {
    145 	size_t len;
    146 	u_long cnt;
    147 	int isempty;
    148 	ARG_CHAR_T key;
    149 	CHAR_T *endp, *p, *startp;
    150 
    151 	/*
    152 	 * !!!
    153 	 * If it's a dot command, it doesn't reset the key for which we're
    154 	 * searching, e.g. in "df1|f2|.|;", the ';' searches for a '2'.
    155 	 */
    156 	key = vp->character;
    157 	if (!F_ISSET(vp, VC_ISDOT))
    158 		VIP(sp)->lastckey = key;
    159 	VIP(sp)->csearchdir = fSEARCH;
    160 
    161 	if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) {
    162 		if (isempty)
    163 			goto empty;
    164 		return (1);
    165 	}
    166 
    167 	if (len == 0) {
    168 empty:		notfound(sp, key);
    169 		return (1);
    170 	}
    171 
    172 	endp = (startp = p) + len;
    173 	p += vp->m_start.cno;
    174 	for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
    175 		while (++p < endp && *p != key);
    176 		if (p == endp) {
    177 			notfound(sp, key);
    178 			return (1);
    179 		}
    180 	}
    181 
    182 	vp->m_stop.cno = p - startp;
    183 
    184 	/*
    185 	 * Non-motion commands move to the end of the range.
    186 	 * Delete and yank stay at the start, ignore others.
    187 	 */
    188 	vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop;
    189 	return (0);
    190 }
    191 
    192 /*
    193  * v_chT -- [count]Tc
    194  *	Search backward in the line for the character after the next
    195  *	occurrence of the specified character.
    196  *
    197  * PUBLIC: int v_chT __P((SCR *, VICMD *));
    198  */
    199 int
    200 v_chT(SCR *sp, VICMD *vp)
    201 {
    202 	if (v_chF(sp, vp))
    203 		return (1);
    204 
    205 	/*
    206 	 * v_chF places the cursor on the character, where the 'T'
    207 	 * command wants it to its right.  We know this is safe since
    208 	 * we had to move left for v_chF() to have succeeded.
    209 	 */
    210 	++vp->m_stop.cno;
    211 	vp->m_final = vp->m_stop;
    212 
    213 	VIP(sp)->csearchdir = TSEARCH;
    214 	return (0);
    215 }
    216 
    217 /*
    218  * v_chF -- [count]Fc
    219  *	Search backward in the line for the next occurrence of the
    220  *	specified character.
    221  *
    222  * PUBLIC: int v_chF __P((SCR *, VICMD *));
    223  */
    224 int
    225 v_chF(SCR *sp, VICMD *vp)
    226 {
    227 	size_t len;
    228 	u_long cnt;
    229 	int isempty;
    230 	ARG_CHAR_T key;
    231 	CHAR_T *endp, *p;
    232 
    233 	/*
    234 	 * !!!
    235 	 * If it's a dot command, it doesn't reset the key for which
    236 	 * we're searching, e.g. in "df1|f2|.|;", the ';' searches
    237 	 * for a '2'.
    238 	 */
    239 	key = vp->character;
    240 	if (!F_ISSET(vp, VC_ISDOT))
    241 		VIP(sp)->lastckey = key;
    242 	VIP(sp)->csearchdir = FSEARCH;
    243 
    244 	if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) {
    245 		if (isempty)
    246 			goto empty;
    247 		return (1);
    248 	}
    249 
    250 	if (len == 0) {
    251 empty:		notfound(sp, key);
    252 		return (1);
    253 	}
    254 
    255 	endp = p - 1;
    256 	p += vp->m_start.cno;
    257 	for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) {
    258 		while (--p > endp && *p != key);
    259 		if (p == endp) {
    260 			notfound(sp, key);
    261 			return (1);
    262 		}
    263 	}
    264 
    265 	vp->m_stop.cno = (p - endp) - 1;
    266 
    267 	/*
    268 	 * All commands move to the end of the range.  Motion commands
    269 	 * adjust the starting point to the character before the current
    270 	 * one.
    271 	 */
    272 	vp->m_final = vp->m_stop;
    273 	if (ISMOTION(vp))
    274 		--vp->m_start.cno;
    275 	return (0);
    276 }
    277 
    278 static void
    279 noprev(SCR *sp)
    280 {
    281 	msgq(sp, M_BERR, "178|No previous F, f, T or t search");
    282 }
    283 
    284 static void
    285 notfound(SCR *sp, ARG_CHAR_T ch)
    286 {
    287 	msgq(sp, M_BERR, "179|%s not found", KEY_NAME(sp, ch));
    288 }
    289