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