1/* $NetBSD: v_ch.c,v 1.2 2013/11/22 15:52:06 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 16static 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$"); 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 34static void notfound __P((SCR *, ARG_CHAR_T)); 35static 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 */ 43int 44v_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 */ 72int 73v_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 */ 111int 112v_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 */ 142int 143v_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) { 168empty: 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 */ 199int 200v_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 */ 224int 225v_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) { 251empty: 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 278static void 279noprev(SCR *sp) 280{ 281 msgq(sp, M_BERR, "178|No previous F, f, T or t search"); 282} 283 284static void 285notfound(SCR *sp, ARG_CHAR_T ch) 286{ 287 msgq(sp, M_BERR, "179|%s not found", KEY_NAME(sp, ch)); 288} 289