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.11 2011/12/02 19:49:50 zy Exp $"; 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; 142 ARG_CHAR_T key; 143 CHAR_T *endp, *p, *startp; 144 145 /* 146 * !!! 147 * If it's a dot command, it doesn't reset the key for which we're 148 * searching, e.g. in "df1|f2|.|;", the ';' searches for a '2'. 149 */ 150 key = vp->character; 151 if (!F_ISSET(vp, VC_ISDOT)) 152 VIP(sp)->lastckey = key; 153 VIP(sp)->csearchdir = fSEARCH; 154 155 if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) { 156 if (isempty) 157 goto empty; 158 return (1); 159 } 160 161 if (len == 0) { 162 empty: notfound(sp, key); 163 return (1); 164 } 165 166 endp = (startp = p) + len; 167 p += vp->m_start.cno; 168 for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) { 169 while (++p < endp && *p != key); 170 if (p == endp) { 171 notfound(sp, key); 172 return (1); 173 } 174 } 175 176 vp->m_stop.cno = p - startp; 177 178 /* 179 * Non-motion commands move to the end of the range. 180 * Delete and yank stay at the start, ignore others. 181 */ 182 vp->m_final = ISMOTION(vp) ? vp->m_start : vp->m_stop; 183 return (0); 184 } 185 186 /* 187 * v_chT -- [count]Tc 188 * Search backward in the line for the character after the next 189 * occurrence of the specified character. 190 * 191 * PUBLIC: int v_chT __P((SCR *, VICMD *)); 192 */ 193 int 194 v_chT(SCR *sp, VICMD *vp) 195 { 196 if (v_chF(sp, vp)) 197 return (1); 198 199 /* 200 * v_chF places the cursor on the character, where the 'T' 201 * command wants it to its right. We know this is safe since 202 * we had to move left for v_chF() to have succeeded. 203 */ 204 ++vp->m_stop.cno; 205 vp->m_final = vp->m_stop; 206 207 VIP(sp)->csearchdir = TSEARCH; 208 return (0); 209 } 210 211 /* 212 * v_chF -- [count]Fc 213 * Search backward in the line for the next occurrence of the 214 * specified character. 215 * 216 * PUBLIC: int v_chF __P((SCR *, VICMD *)); 217 */ 218 int 219 v_chF(SCR *sp, VICMD *vp) 220 { 221 size_t len; 222 u_long cnt; 223 int isempty; 224 ARG_CHAR_T key; 225 CHAR_T *endp, *p; 226 227 /* 228 * !!! 229 * If it's a dot command, it doesn't reset the key for which 230 * we're searching, e.g. in "df1|f2|.|;", the ';' searches 231 * for a '2'. 232 */ 233 key = vp->character; 234 if (!F_ISSET(vp, VC_ISDOT)) 235 VIP(sp)->lastckey = key; 236 VIP(sp)->csearchdir = FSEARCH; 237 238 if (db_eget(sp, vp->m_start.lno, &p, &len, &isempty)) { 239 if (isempty) 240 goto empty; 241 return (1); 242 } 243 244 if (len == 0) { 245 empty: notfound(sp, key); 246 return (1); 247 } 248 249 endp = p - 1; 250 p += vp->m_start.cno; 251 for (cnt = F_ISSET(vp, VC_C1SET) ? vp->count : 1; cnt--;) { 252 while (--p > endp && *p != key); 253 if (p == endp) { 254 notfound(sp, key); 255 return (1); 256 } 257 } 258 259 vp->m_stop.cno = (p - endp) - 1; 260 261 /* 262 * All commands move to the end of the range. Motion commands 263 * adjust the starting point to the character before the current 264 * one. 265 */ 266 vp->m_final = vp->m_stop; 267 if (ISMOTION(vp)) 268 --vp->m_start.cno; 269 return (0); 270 } 271 272 static void 273 noprev(SCR *sp) 274 { 275 msgq(sp, M_BERR, "178|No previous F, f, T or t search"); 276 } 277 278 static void 279 notfound(SCR *sp, ARG_CHAR_T ch) 280 { 281 msgq(sp, M_BERR, "179|%s not found", KEY_NAME(sp, ch)); 282 } 283