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