10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 22*802Scf46844 /* 23*802Scf46844 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*802Scf46844 * Use is subject to license terms. 25*802Scf46844 */ 26*802Scf46844 270Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 280Sstevel@tonic-gate /* All Rights Reserved */ 290Sstevel@tonic-gate 300Sstevel@tonic-gate 310Sstevel@tonic-gate /* 320Sstevel@tonic-gate * Copyright (c) 1981 Regents of the University of California 330Sstevel@tonic-gate */ 340Sstevel@tonic-gate 350Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 36*802Scf46844 370Sstevel@tonic-gate #include "ex.h" 380Sstevel@tonic-gate #include "ex_tty.h" 390Sstevel@tonic-gate #include "ex_vis.h" 400Sstevel@tonic-gate #include <regexpr.h> 410Sstevel@tonic-gate #ifndef PRESUNEUC 420Sstevel@tonic-gate #include <wctype.h> 430Sstevel@tonic-gate /* Undef putchar/getchar if they're defined. */ 440Sstevel@tonic-gate #ifdef putchar 450Sstevel@tonic-gate #undef putchar 460Sstevel@tonic-gate #endif 470Sstevel@tonic-gate #ifdef getchar 480Sstevel@tonic-gate #undef getchar 490Sstevel@tonic-gate #endif 500Sstevel@tonic-gate #endif /* PRESUNEUC */ 510Sstevel@tonic-gate 520Sstevel@tonic-gate #ifdef PRESUNEUC 530Sstevel@tonic-gate #define blank() isspace(wcursor[0]) 540Sstevel@tonic-gate #endif /* PRESUNEUC */ 550Sstevel@tonic-gate #define forbid(a) if (a) goto errlab; 560Sstevel@tonic-gate 570Sstevel@tonic-gate unsigned char vscandir[2] = { '/', 0 }; 580Sstevel@tonic-gate 590Sstevel@tonic-gate /* 600Sstevel@tonic-gate * Decode an operator/operand type command. 610Sstevel@tonic-gate * Eventually we switch to an operator subroutine in ex_vops.c. 620Sstevel@tonic-gate * The work here is setting up a function variable to point 630Sstevel@tonic-gate * to the routine we want, and manipulation of the variables 640Sstevel@tonic-gate * wcursor and wdot, which mark the other end of the affected 650Sstevel@tonic-gate * area. If wdot is zero, then the current line is the other end, 660Sstevel@tonic-gate * and if wcursor is zero, then the first non-blank location of the 670Sstevel@tonic-gate * other line is implied. 680Sstevel@tonic-gate */ 69*802Scf46844 void 70*802Scf46844 operate(int c, int cnt) 710Sstevel@tonic-gate { 72*802Scf46844 wchar_t i; 730Sstevel@tonic-gate int (*moveop)(), (*deleteop)(); 74*802Scf46844 int (*opf)(); 750Sstevel@tonic-gate bool subop = 0; 760Sstevel@tonic-gate unsigned char *oglobp, *ocurs; 77*802Scf46844 line *addr; 780Sstevel@tonic-gate line *odot; 790Sstevel@tonic-gate int oc; 800Sstevel@tonic-gate static unsigned char lastFKND; 810Sstevel@tonic-gate static wchar_t lastFCHR; 820Sstevel@tonic-gate short d; 830Sstevel@tonic-gate /* #ifdef PTR_ADDRESSES */ 840Sstevel@tonic-gate int mouse_x; 850Sstevel@tonic-gate int mouse_y; 860Sstevel@tonic-gate int oline; 870Sstevel@tonic-gate static int get_addr(); 880Sstevel@tonic-gate /* #endif PTR_ADDRESSES */ 890Sstevel@tonic-gate 90*802Scf46844 moveop = vmove, deleteop = (int (*)())vdelete; 910Sstevel@tonic-gate wcursor = cursor; 920Sstevel@tonic-gate wdot = NOLINE; 930Sstevel@tonic-gate notecnt = 0; 940Sstevel@tonic-gate dir = 1; 950Sstevel@tonic-gate switch (c) { 960Sstevel@tonic-gate 970Sstevel@tonic-gate /* 980Sstevel@tonic-gate * d delete operator. 990Sstevel@tonic-gate */ 1000Sstevel@tonic-gate case 'd': 101*802Scf46844 moveop = (int (*)())vdelete; 1020Sstevel@tonic-gate deleteop = beep; 1030Sstevel@tonic-gate break; 1040Sstevel@tonic-gate 1050Sstevel@tonic-gate /* 1060Sstevel@tonic-gate * s substitute characters, like c\040, i.e. change space. 1070Sstevel@tonic-gate */ 1080Sstevel@tonic-gate case 's': 1090Sstevel@tonic-gate ungetkey(' '); 1100Sstevel@tonic-gate subop++; 1110Sstevel@tonic-gate /* fall into ... */ 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate /* 1140Sstevel@tonic-gate * c Change operator. 1150Sstevel@tonic-gate */ 1160Sstevel@tonic-gate case 'c': 1170Sstevel@tonic-gate if (c == 'c' && workcmd[0] == 'C' || workcmd[0] == 'S') 1180Sstevel@tonic-gate subop++; 119*802Scf46844 moveop = (int (*)())vchange; 1200Sstevel@tonic-gate deleteop = beep; 1210Sstevel@tonic-gate break; 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate /* 1240Sstevel@tonic-gate * ! Filter through a UNIX command. 1250Sstevel@tonic-gate */ 1260Sstevel@tonic-gate case '!': 1270Sstevel@tonic-gate moveop = vfilter; 1280Sstevel@tonic-gate deleteop = beep; 1290Sstevel@tonic-gate break; 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate /* 1320Sstevel@tonic-gate * y Yank operator. Place specified text so that it 1330Sstevel@tonic-gate * can be put back with p/P. Also yanks to named buffers. 1340Sstevel@tonic-gate */ 1350Sstevel@tonic-gate case 'y': 1360Sstevel@tonic-gate moveop = vyankit; 1370Sstevel@tonic-gate deleteop = beep; 1380Sstevel@tonic-gate break; 1390Sstevel@tonic-gate 1400Sstevel@tonic-gate /* 1410Sstevel@tonic-gate * = Reformat operator (for LISP). 1420Sstevel@tonic-gate */ 1430Sstevel@tonic-gate case '=': 1440Sstevel@tonic-gate forbid(!value(vi_LISP)); 1450Sstevel@tonic-gate /* fall into ... */ 1460Sstevel@tonic-gate 1470Sstevel@tonic-gate /* 1480Sstevel@tonic-gate * > Right shift operator. 1490Sstevel@tonic-gate * < Left shift operator. 1500Sstevel@tonic-gate */ 1510Sstevel@tonic-gate case '<': 1520Sstevel@tonic-gate case '>': 1530Sstevel@tonic-gate moveop = vshftop; 1540Sstevel@tonic-gate deleteop = beep; 1550Sstevel@tonic-gate break; 1560Sstevel@tonic-gate 1570Sstevel@tonic-gate /* 1580Sstevel@tonic-gate * r Replace character under cursor with single following 1590Sstevel@tonic-gate * character. 1600Sstevel@tonic-gate */ 1610Sstevel@tonic-gate case 'r': 1620Sstevel@tonic-gate vmacchng(1); 1630Sstevel@tonic-gate vrep(cnt); 1640Sstevel@tonic-gate return; 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate default: 1670Sstevel@tonic-gate goto nocount; 1680Sstevel@tonic-gate } 1690Sstevel@tonic-gate vmacchng(1); 1700Sstevel@tonic-gate /* 1710Sstevel@tonic-gate * Had an operator, so accept another count. 1720Sstevel@tonic-gate * Multiply counts together. 1730Sstevel@tonic-gate */ 1740Sstevel@tonic-gate if (isdigit(peekkey()) && peekkey() != '0') { 1750Sstevel@tonic-gate cnt *= vgetcnt(); 1760Sstevel@tonic-gate Xcnt = cnt; 1770Sstevel@tonic-gate forbid(cnt <= 0); 1780Sstevel@tonic-gate } 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate /* 1810Sstevel@tonic-gate * Get next character, mapping it and saving as 1820Sstevel@tonic-gate * part of command for repeat. 1830Sstevel@tonic-gate */ 1840Sstevel@tonic-gate c = map(getesc(), arrows, 0); 1850Sstevel@tonic-gate if (c == 0) 1860Sstevel@tonic-gate return; 1870Sstevel@tonic-gate if (!subop) 1880Sstevel@tonic-gate *lastcp++ = c; 1890Sstevel@tonic-gate nocount: 1900Sstevel@tonic-gate opf = moveop; 1910Sstevel@tonic-gate switch (c) { 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate /* #ifdef PTR_ADDRESSES */ 1940Sstevel@tonic-gate /* 1950Sstevel@tonic-gate * ^X^_ Netty Mouse positioning hack 1960Sstevel@tonic-gate * ^X^] 1970Sstevel@tonic-gate */ 1980Sstevel@tonic-gate case CTRL('X'): 1990Sstevel@tonic-gate /* 2000Sstevel@tonic-gate * Read in mouse stuff 2010Sstevel@tonic-gate */ 2020Sstevel@tonic-gate c = getkey(); /* ^_ or ^] */ 2030Sstevel@tonic-gate if ((c != CTRL('_')) && (c != (CTRL(']')))) 2040Sstevel@tonic-gate break; 2050Sstevel@tonic-gate getkey(); /* mouse button */ 2060Sstevel@tonic-gate mouse_x = get_addr() + 1; 2070Sstevel@tonic-gate mouse_y = get_addr() + 1; 2080Sstevel@tonic-gate if (mouse_y < WTOP) 2090Sstevel@tonic-gate break; 2100Sstevel@tonic-gate if (Pline == numbline) 2110Sstevel@tonic-gate mouse_x -= 8; 2120Sstevel@tonic-gate if (mouse_x < 0) 2130Sstevel@tonic-gate mouse_x = 0; 2140Sstevel@tonic-gate if (mouse_x > WCOLS) 2150Sstevel@tonic-gate break; 2160Sstevel@tonic-gate /* 2170Sstevel@tonic-gate * Find the line on the screen 2180Sstevel@tonic-gate */ 2190Sstevel@tonic-gate for (i = 0; i <= WECHO; i++) 2200Sstevel@tonic-gate { 2210Sstevel@tonic-gate if (vlinfo[i].vliny >= mouse_y) 2220Sstevel@tonic-gate break; 2230Sstevel@tonic-gate } 2240Sstevel@tonic-gate if (i > WECHO) 2250Sstevel@tonic-gate break; 2260Sstevel@tonic-gate /* 2270Sstevel@tonic-gate * Look for lines longer than one line - note odd case at zero 2280Sstevel@tonic-gate */ 2290Sstevel@tonic-gate if (i) 2300Sstevel@tonic-gate { 2310Sstevel@tonic-gate if (vlinfo[i - 1].vdepth > 1) 2320Sstevel@tonic-gate { 2330Sstevel@tonic-gate mouse_x += WCOLS * (mouse_y - 2340Sstevel@tonic-gate (vlinfo[i].vliny - 2350Sstevel@tonic-gate (vlinfo[i - 1].vdepth - 1))); 2360Sstevel@tonic-gate } 2370Sstevel@tonic-gate } 2380Sstevel@tonic-gate else 2390Sstevel@tonic-gate { 2400Sstevel@tonic-gate mouse_x += WCOLS * (mouse_y - 1); 2410Sstevel@tonic-gate } 2420Sstevel@tonic-gate /* 2430Sstevel@tonic-gate * Set the line 2440Sstevel@tonic-gate */ 2450Sstevel@tonic-gate vsave(); 2460Sstevel@tonic-gate ocurs = cursor; 2470Sstevel@tonic-gate odot = dot; 2480Sstevel@tonic-gate oline = vcline; 2490Sstevel@tonic-gate operate('H', i); 2500Sstevel@tonic-gate /* 2510Sstevel@tonic-gate * Set the column 2520Sstevel@tonic-gate */ 2530Sstevel@tonic-gate getDOT(); 2540Sstevel@tonic-gate if (Pline == numbline) 2550Sstevel@tonic-gate mouse_x += 8; 2560Sstevel@tonic-gate vmovcol = mouse_x; 2570Sstevel@tonic-gate vmoving = 1; 2580Sstevel@tonic-gate wcursor = vfindcol(mouse_x); 2590Sstevel@tonic-gate /* 2600Sstevel@tonic-gate * Reset everything so that stuff like delete and change work 2610Sstevel@tonic-gate */ 2620Sstevel@tonic-gate wdot = (odot - oline) + i - 1; 2630Sstevel@tonic-gate cursor = ocurs; 2640Sstevel@tonic-gate vcline = oline; 2650Sstevel@tonic-gate dot = odot; 2660Sstevel@tonic-gate getDOT(); 2670Sstevel@tonic-gate break; 2680Sstevel@tonic-gate /* #endif PTR_ADDRESSES */ 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate /* 2710Sstevel@tonic-gate * b Back up a word. 2720Sstevel@tonic-gate * B Back up a word, liberal definition. 2730Sstevel@tonic-gate */ 2740Sstevel@tonic-gate case 'b': 2750Sstevel@tonic-gate case 'B': 2760Sstevel@tonic-gate dir = -1; 2770Sstevel@tonic-gate /* fall into ... */ 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate /* 2800Sstevel@tonic-gate * w Forward a word. 2810Sstevel@tonic-gate * W Forward a word, liberal definition. 2820Sstevel@tonic-gate */ 2830Sstevel@tonic-gate case 'W': 2840Sstevel@tonic-gate case 'w': 2850Sstevel@tonic-gate wdkind = c & ' '; 2860Sstevel@tonic-gate forbid(lfind(2, cnt, opf, (line *)0) < 0); 2870Sstevel@tonic-gate vmoving = 0; 2880Sstevel@tonic-gate break; 2890Sstevel@tonic-gate 2900Sstevel@tonic-gate /* 2910Sstevel@tonic-gate * E to end of following blank/nonblank word 2920Sstevel@tonic-gate */ 2930Sstevel@tonic-gate case 'E': 2940Sstevel@tonic-gate wdkind = 0; 2950Sstevel@tonic-gate goto ein; 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate /* 2980Sstevel@tonic-gate * e To end of following word. 2990Sstevel@tonic-gate */ 3000Sstevel@tonic-gate case 'e': 3010Sstevel@tonic-gate wdkind = 1; 3020Sstevel@tonic-gate ein: 3030Sstevel@tonic-gate forbid(lfind(3, cnt - 1, opf, (line *)0) < 0); 3040Sstevel@tonic-gate vmoving = 0; 3050Sstevel@tonic-gate break; 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate /* 3080Sstevel@tonic-gate * ( Back an s-expression. 3090Sstevel@tonic-gate */ 3100Sstevel@tonic-gate case '(': 3110Sstevel@tonic-gate dir = -1; 3120Sstevel@tonic-gate /* fall into... */ 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate /* 3150Sstevel@tonic-gate * ) Forward an s-expression. 3160Sstevel@tonic-gate */ 3170Sstevel@tonic-gate case ')': 3180Sstevel@tonic-gate forbid(lfind(0, cnt, opf, (line *) 0) < 0); 3190Sstevel@tonic-gate markDOT(); 3200Sstevel@tonic-gate break; 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate /* 3230Sstevel@tonic-gate * { Back an s-expression, but don't stop on atoms. 3240Sstevel@tonic-gate * In text mode, a paragraph. For C, a balanced set 3250Sstevel@tonic-gate * of {}'s. 3260Sstevel@tonic-gate */ 3270Sstevel@tonic-gate case '{': 3280Sstevel@tonic-gate dir = -1; 3290Sstevel@tonic-gate /* fall into... */ 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate /* 3320Sstevel@tonic-gate * } Forward an s-expression, but don't stop on atoms. 3330Sstevel@tonic-gate * In text mode, back paragraph. For C, back a balanced 3340Sstevel@tonic-gate * set of {}'s. 3350Sstevel@tonic-gate */ 3360Sstevel@tonic-gate case '}': 3370Sstevel@tonic-gate forbid(lfind(1, cnt, opf, (line *) 0) < 0); 3380Sstevel@tonic-gate markDOT(); 3390Sstevel@tonic-gate break; 3400Sstevel@tonic-gate 3410Sstevel@tonic-gate /* 3420Sstevel@tonic-gate * % To matching () or {}. If not at ( or { scan for 3430Sstevel@tonic-gate * first such after cursor on this line. 3440Sstevel@tonic-gate */ 3450Sstevel@tonic-gate case '%': 3460Sstevel@tonic-gate vsave(); 3470Sstevel@tonic-gate ocurs = cursor; 3480Sstevel@tonic-gate odot = wdot = dot; 3490Sstevel@tonic-gate oglobp = globp; 3500Sstevel@tonic-gate CATCH 3510Sstevel@tonic-gate i = lmatchp((line *) 0); 3520Sstevel@tonic-gate ONERR 3530Sstevel@tonic-gate globp = oglobp; 3540Sstevel@tonic-gate dot = wdot = odot; 3550Sstevel@tonic-gate cursor = ocurs; 3560Sstevel@tonic-gate splitw = 0; 3570Sstevel@tonic-gate vclean(); 3580Sstevel@tonic-gate vjumpto(dot, ocurs, 0); 3590Sstevel@tonic-gate return; 3600Sstevel@tonic-gate ENDCATCH 3610Sstevel@tonic-gate #ifdef TRACE 3620Sstevel@tonic-gate if (trace) 3630Sstevel@tonic-gate fprintf(trace, "after lmatchp in %, dot=%d, wdot=%d, " 3640Sstevel@tonic-gate "dol=%d\n", lineno(dot), lineno(wdot), lineno(dol)); 3650Sstevel@tonic-gate #endif 3660Sstevel@tonic-gate getDOT(); 3670Sstevel@tonic-gate forbid(!i); 3680Sstevel@tonic-gate if (opf != vmove) 3690Sstevel@tonic-gate if (dir > 0) 3700Sstevel@tonic-gate wcursor++; 3710Sstevel@tonic-gate else 3720Sstevel@tonic-gate cursor++; 3730Sstevel@tonic-gate else 3740Sstevel@tonic-gate markDOT(); 3750Sstevel@tonic-gate vmoving = 0; 3760Sstevel@tonic-gate break; 3770Sstevel@tonic-gate 3780Sstevel@tonic-gate /* 3790Sstevel@tonic-gate * [ Back to beginning of defun, i.e. an ( in column 1. 3800Sstevel@tonic-gate * For text, back to a section macro. 3810Sstevel@tonic-gate * For C, back to a { in column 1 (~~ beg of function.) 3820Sstevel@tonic-gate */ 3830Sstevel@tonic-gate case '[': 3840Sstevel@tonic-gate dir = -1; 3850Sstevel@tonic-gate /* fall into ... */ 3860Sstevel@tonic-gate 3870Sstevel@tonic-gate /* 3880Sstevel@tonic-gate * ] Forward to next defun, i.e. a ( in column 1. 3890Sstevel@tonic-gate * For text, forward section. 3900Sstevel@tonic-gate * For C, forward to a } in column 1 (if delete or such) 3910Sstevel@tonic-gate * or if a move to a { in column 1. 3920Sstevel@tonic-gate */ 3930Sstevel@tonic-gate case ']': 3940Sstevel@tonic-gate if (!vglobp) 3950Sstevel@tonic-gate forbid(getkey() != c); 3960Sstevel@tonic-gate #ifndef XPG4 3970Sstevel@tonic-gate forbid(Xhadcnt); 3980Sstevel@tonic-gate #endif 3990Sstevel@tonic-gate vsave(); 4000Sstevel@tonic-gate #ifdef XPG4 4010Sstevel@tonic-gate if (cnt > 1) { 4020Sstevel@tonic-gate while (cnt-- > 1) { 4030Sstevel@tonic-gate i = lbrack(c, opf); 4040Sstevel@tonic-gate getDOT(); 4050Sstevel@tonic-gate forbid(!i); 4060Sstevel@tonic-gate markDOT(); 4070Sstevel@tonic-gate if (ospeed > B300) 4080Sstevel@tonic-gate hold |= HOLDWIG; 4090Sstevel@tonic-gate (*opf)(c); 4100Sstevel@tonic-gate } 4110Sstevel@tonic-gate } 4120Sstevel@tonic-gate #endif /* XPG4 */ 4130Sstevel@tonic-gate i = lbrack(c, opf); 4140Sstevel@tonic-gate getDOT(); 4150Sstevel@tonic-gate forbid(!i); 4160Sstevel@tonic-gate markDOT(); 4170Sstevel@tonic-gate if (ospeed > B300) 4180Sstevel@tonic-gate hold |= HOLDWIG; 4190Sstevel@tonic-gate break; 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate /* 4220Sstevel@tonic-gate * , Invert last find with f F t or T, like inverse 4230Sstevel@tonic-gate * of ;. 4240Sstevel@tonic-gate */ 4250Sstevel@tonic-gate case ',': 4260Sstevel@tonic-gate forbid(lastFKND == 0); 4270Sstevel@tonic-gate c = isupper(lastFKND) ? tolower(lastFKND) : toupper(lastFKND); 4280Sstevel@tonic-gate i = lastFCHR; 4290Sstevel@tonic-gate if (vglobp == 0) 4300Sstevel@tonic-gate vglobp = (unsigned char *)""; 4310Sstevel@tonic-gate subop++; 4320Sstevel@tonic-gate goto nocount; 4330Sstevel@tonic-gate 4340Sstevel@tonic-gate /* 4350Sstevel@tonic-gate * 0 To beginning of real line. 4360Sstevel@tonic-gate */ 4370Sstevel@tonic-gate case '0': 4380Sstevel@tonic-gate wcursor = linebuf; 4390Sstevel@tonic-gate vmoving = 0; 4400Sstevel@tonic-gate break; 4410Sstevel@tonic-gate 4420Sstevel@tonic-gate /* 4430Sstevel@tonic-gate * ; Repeat last find with f F t or T. 4440Sstevel@tonic-gate */ 4450Sstevel@tonic-gate case ';': 4460Sstevel@tonic-gate forbid(lastFKND == 0); 4470Sstevel@tonic-gate c = lastFKND; 4480Sstevel@tonic-gate i = lastFCHR; 4490Sstevel@tonic-gate subop++; 4500Sstevel@tonic-gate goto nocount; 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate /* 4530Sstevel@tonic-gate * F Find single character before cursor in current line. 4540Sstevel@tonic-gate * T Like F, but stops before character. 4550Sstevel@tonic-gate */ 4560Sstevel@tonic-gate case 'F': /* inverted find */ 4570Sstevel@tonic-gate case 'T': 4580Sstevel@tonic-gate dir = -1; 4590Sstevel@tonic-gate /* fall into ... */ 4600Sstevel@tonic-gate 4610Sstevel@tonic-gate /* 4620Sstevel@tonic-gate * f Find single character following cursor in current line. 4630Sstevel@tonic-gate * t Like f, but stope before character. 4640Sstevel@tonic-gate */ 4650Sstevel@tonic-gate case 'f': /* find */ 4660Sstevel@tonic-gate case 't': 4670Sstevel@tonic-gate if (!subop) { 4680Sstevel@tonic-gate int length; 4690Sstevel@tonic-gate wchar_t wchar; 4700Sstevel@tonic-gate length = _mbftowc(lastcp, &wchar, getesc, &Peekkey); 4710Sstevel@tonic-gate if (length <= 0 || wchar == 0) { 472*802Scf46844 (void) beep(); 4730Sstevel@tonic-gate return; 4740Sstevel@tonic-gate } 4750Sstevel@tonic-gate i = wchar; 4760Sstevel@tonic-gate lastcp += length; 4770Sstevel@tonic-gate } 4780Sstevel@tonic-gate if (vglobp == 0) 4790Sstevel@tonic-gate lastFKND = c, lastFCHR = i; 4800Sstevel@tonic-gate for (; cnt > 0; cnt--) 4810Sstevel@tonic-gate forbid(find(i) == 0); 4820Sstevel@tonic-gate vmoving = 0; 4830Sstevel@tonic-gate switch (c) { 4840Sstevel@tonic-gate 4850Sstevel@tonic-gate case 'T': 4860Sstevel@tonic-gate wcursor = nextchr(wcursor); 4870Sstevel@tonic-gate break; 4880Sstevel@tonic-gate 4890Sstevel@tonic-gate case 't': 4900Sstevel@tonic-gate wcursor = lastchr(linebuf, wcursor); 4910Sstevel@tonic-gate case 'f': 4920Sstevel@tonic-gate fixup: 4930Sstevel@tonic-gate if (moveop != vmove) 4940Sstevel@tonic-gate wcursor = nextchr(wcursor); 4950Sstevel@tonic-gate break; 4960Sstevel@tonic-gate } 4970Sstevel@tonic-gate break; 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate /* 5000Sstevel@tonic-gate * | Find specified print column in current line. 5010Sstevel@tonic-gate */ 5020Sstevel@tonic-gate case '|': 5030Sstevel@tonic-gate if (Pline == numbline) 5040Sstevel@tonic-gate cnt += 8; 5050Sstevel@tonic-gate vmovcol = cnt; 5060Sstevel@tonic-gate vmoving = 1; 5070Sstevel@tonic-gate wcursor = vfindcol(cnt); 5080Sstevel@tonic-gate break; 5090Sstevel@tonic-gate 5100Sstevel@tonic-gate /* 5110Sstevel@tonic-gate * ^ To beginning of non-white space on line. 5120Sstevel@tonic-gate */ 5130Sstevel@tonic-gate case '^': 5140Sstevel@tonic-gate wcursor = vskipwh(linebuf); 5150Sstevel@tonic-gate vmoving = 0; 5160Sstevel@tonic-gate break; 5170Sstevel@tonic-gate 5180Sstevel@tonic-gate /* 5190Sstevel@tonic-gate * $ To end of line. 5200Sstevel@tonic-gate */ 5210Sstevel@tonic-gate case '$': 5220Sstevel@tonic-gate if (opf == vmove) { 5230Sstevel@tonic-gate vmoving = 1; 5240Sstevel@tonic-gate vmovcol = 20000; 5250Sstevel@tonic-gate } else 5260Sstevel@tonic-gate vmoving = 0; 5270Sstevel@tonic-gate if (cnt > 1) { 5280Sstevel@tonic-gate if (opf == vmove) { 5290Sstevel@tonic-gate wcursor = 0; 5300Sstevel@tonic-gate cnt--; 5310Sstevel@tonic-gate } else 5320Sstevel@tonic-gate wcursor = linebuf; 5330Sstevel@tonic-gate /* This is wrong at EOF */ 5340Sstevel@tonic-gate wdot = dot + cnt; 5350Sstevel@tonic-gate break; 5360Sstevel@tonic-gate } 5370Sstevel@tonic-gate if (linebuf[0]) { 5380Sstevel@tonic-gate wcursor = strend(linebuf); 5390Sstevel@tonic-gate wcursor = lastchr(linebuf, wcursor); 5400Sstevel@tonic-gate goto fixup; 5410Sstevel@tonic-gate } 5420Sstevel@tonic-gate wcursor = linebuf; 5430Sstevel@tonic-gate break; 5440Sstevel@tonic-gate 5450Sstevel@tonic-gate /* 5460Sstevel@tonic-gate * h Back a character. 5470Sstevel@tonic-gate * ^H Back a character. 5480Sstevel@tonic-gate */ 5490Sstevel@tonic-gate case 'h': 5500Sstevel@tonic-gate case CTRL('h'): 5510Sstevel@tonic-gate dir = -1; 5520Sstevel@tonic-gate /* fall into ... */ 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate /* 5550Sstevel@tonic-gate * space Forward a character. 5560Sstevel@tonic-gate */ 5570Sstevel@tonic-gate case 'l': 5580Sstevel@tonic-gate case ' ': 5590Sstevel@tonic-gate forbid(margin() || opf == vmove && edge()); 5600Sstevel@tonic-gate while (cnt > 0 && !margin()) { 5610Sstevel@tonic-gate if (dir == 1) 5620Sstevel@tonic-gate wcursor = nextchr(wcursor); 5630Sstevel@tonic-gate else 5640Sstevel@tonic-gate wcursor = lastchr(linebuf, wcursor); 5650Sstevel@tonic-gate cnt--; 5660Sstevel@tonic-gate } 5670Sstevel@tonic-gate if (margin() && opf == vmove || wcursor < linebuf) { 5680Sstevel@tonic-gate if (dir == 1) 5690Sstevel@tonic-gate wcursor = lastchr(linebuf, wcursor); 5700Sstevel@tonic-gate else 5710Sstevel@tonic-gate wcursor = linebuf; 5720Sstevel@tonic-gate } 5730Sstevel@tonic-gate vmoving = 0; 5740Sstevel@tonic-gate break; 5750Sstevel@tonic-gate 5760Sstevel@tonic-gate /* 5770Sstevel@tonic-gate * D Delete to end of line, short for d$. 5780Sstevel@tonic-gate */ 5790Sstevel@tonic-gate case 'D': 5800Sstevel@tonic-gate cnt = INF; 5810Sstevel@tonic-gate goto deleteit; 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate /* 5840Sstevel@tonic-gate * X Delete character before cursor. 5850Sstevel@tonic-gate */ 5860Sstevel@tonic-gate case 'X': 5870Sstevel@tonic-gate dir = -1; 5880Sstevel@tonic-gate /* fall into ... */ 5890Sstevel@tonic-gate deleteit: 5900Sstevel@tonic-gate /* 5910Sstevel@tonic-gate * x Delete character at cursor, leaving cursor where it is. 5920Sstevel@tonic-gate */ 5930Sstevel@tonic-gate case 'x': 5940Sstevel@tonic-gate if (margin()) 5950Sstevel@tonic-gate goto errlab; 5960Sstevel@tonic-gate vmacchng(1); 5970Sstevel@tonic-gate while (cnt > 0 && !margin()) { 5980Sstevel@tonic-gate if (dir == 1) 5990Sstevel@tonic-gate wcursor = nextchr(wcursor); 6000Sstevel@tonic-gate else 6010Sstevel@tonic-gate wcursor = lastchr(linebuf, wcursor); 6020Sstevel@tonic-gate cnt--; 6030Sstevel@tonic-gate } 6040Sstevel@tonic-gate opf = deleteop; 6050Sstevel@tonic-gate vmoving = 0; 6060Sstevel@tonic-gate break; 6070Sstevel@tonic-gate 6080Sstevel@tonic-gate default: 6090Sstevel@tonic-gate /* 6100Sstevel@tonic-gate * Stuttered operators are equivalent to the operator on 6110Sstevel@tonic-gate * a line, thus turn dd into d_. 6120Sstevel@tonic-gate */ 6130Sstevel@tonic-gate if (opf == vmove || c != workcmd[0]) { 6140Sstevel@tonic-gate errlab: 615*802Scf46844 (void) beep(); 6160Sstevel@tonic-gate vmacp = 0; 6170Sstevel@tonic-gate return; 6180Sstevel@tonic-gate } 6190Sstevel@tonic-gate /* fall into ... */ 6200Sstevel@tonic-gate 6210Sstevel@tonic-gate /* 6220Sstevel@tonic-gate * _ Target for a line or group of lines. 6230Sstevel@tonic-gate * Stuttering is more convenient; this is mostly 6240Sstevel@tonic-gate * for aesthetics. 6250Sstevel@tonic-gate */ 6260Sstevel@tonic-gate case '_': 6270Sstevel@tonic-gate wdot = dot + cnt - 1; 6280Sstevel@tonic-gate vmoving = 0; 6290Sstevel@tonic-gate wcursor = 0; 6300Sstevel@tonic-gate break; 6310Sstevel@tonic-gate 6320Sstevel@tonic-gate /* 6330Sstevel@tonic-gate * H To first, home line on screen. 6340Sstevel@tonic-gate * Count is for count'th line rather than first. 6350Sstevel@tonic-gate */ 6360Sstevel@tonic-gate case 'H': 6370Sstevel@tonic-gate wdot = (dot - vcline) + cnt - 1; 6380Sstevel@tonic-gate if (opf == vmove) 6390Sstevel@tonic-gate markit(wdot); 6400Sstevel@tonic-gate vmoving = 0; 6410Sstevel@tonic-gate wcursor = 0; 6420Sstevel@tonic-gate break; 6430Sstevel@tonic-gate 6440Sstevel@tonic-gate /* 6450Sstevel@tonic-gate * - Backwards lines, to first non-white character. 6460Sstevel@tonic-gate */ 6470Sstevel@tonic-gate case '-': 6480Sstevel@tonic-gate wdot = dot - cnt; 6490Sstevel@tonic-gate vmoving = 0; 6500Sstevel@tonic-gate wcursor = 0; 6510Sstevel@tonic-gate break; 6520Sstevel@tonic-gate 6530Sstevel@tonic-gate /* 6540Sstevel@tonic-gate * ^P To previous line same column. Ridiculous on the 6550Sstevel@tonic-gate * console of the VAX since it puts console in LSI mode. 6560Sstevel@tonic-gate */ 6570Sstevel@tonic-gate case 'k': 6580Sstevel@tonic-gate case CTRL('p'): 6590Sstevel@tonic-gate wdot = dot - cnt; 6600Sstevel@tonic-gate if (vmoving == 0) 6610Sstevel@tonic-gate vmoving = 1, vmovcol = column(cursor); 6620Sstevel@tonic-gate wcursor = 0; 6630Sstevel@tonic-gate break; 6640Sstevel@tonic-gate 6650Sstevel@tonic-gate /* 6660Sstevel@tonic-gate * L To last line on screen, or count'th line from the 6670Sstevel@tonic-gate * bottom. 6680Sstevel@tonic-gate */ 6690Sstevel@tonic-gate case 'L': 6700Sstevel@tonic-gate wdot = dot + vcnt - vcline - cnt; 6710Sstevel@tonic-gate if (opf == vmove) 6720Sstevel@tonic-gate markit(wdot); 6730Sstevel@tonic-gate vmoving = 0; 6740Sstevel@tonic-gate wcursor = 0; 6750Sstevel@tonic-gate break; 6760Sstevel@tonic-gate 6770Sstevel@tonic-gate /* 6780Sstevel@tonic-gate * M To the middle of the screen. 6790Sstevel@tonic-gate */ 6800Sstevel@tonic-gate case 'M': 6810Sstevel@tonic-gate wdot = dot + ((vcnt + 1) / 2) - vcline - 1; 6820Sstevel@tonic-gate if (opf == vmove) 6830Sstevel@tonic-gate markit(wdot); 6840Sstevel@tonic-gate vmoving = 0; 6850Sstevel@tonic-gate wcursor = 0; 6860Sstevel@tonic-gate break; 6870Sstevel@tonic-gate 6880Sstevel@tonic-gate /* 6890Sstevel@tonic-gate * + Forward line, to first non-white. 6900Sstevel@tonic-gate * 6910Sstevel@tonic-gate * CR Convenient synonym for +. 6920Sstevel@tonic-gate */ 6930Sstevel@tonic-gate case '+': 6940Sstevel@tonic-gate case CR: 6950Sstevel@tonic-gate wdot = dot + cnt; 6960Sstevel@tonic-gate vmoving = 0; 6970Sstevel@tonic-gate wcursor = 0; 6980Sstevel@tonic-gate break; 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate /* 7010Sstevel@tonic-gate * ^N To next line, same column if possible. 7020Sstevel@tonic-gate * 7030Sstevel@tonic-gate * LF Linefeed is a convenient synonym for ^N. 7040Sstevel@tonic-gate */ 7050Sstevel@tonic-gate case CTRL('n'): 7060Sstevel@tonic-gate case 'j': 7070Sstevel@tonic-gate case NL: 7080Sstevel@tonic-gate wdot = dot + cnt; 7090Sstevel@tonic-gate if (vmoving == 0) 7100Sstevel@tonic-gate vmoving = 1, vmovcol = column(cursor); 7110Sstevel@tonic-gate wcursor = 0; 7120Sstevel@tonic-gate break; 7130Sstevel@tonic-gate 7140Sstevel@tonic-gate /* 7150Sstevel@tonic-gate * n Search to next match of current pattern. 7160Sstevel@tonic-gate */ 7170Sstevel@tonic-gate case 'n': 7180Sstevel@tonic-gate vglobp = vscandir; 7190Sstevel@tonic-gate c = *vglobp++; 7200Sstevel@tonic-gate goto nocount; 7210Sstevel@tonic-gate 7220Sstevel@tonic-gate /* 7230Sstevel@tonic-gate * N Like n but in reverse direction. 7240Sstevel@tonic-gate */ 7250Sstevel@tonic-gate case 'N': 7260Sstevel@tonic-gate vglobp = vscandir[0] == '/' ? (unsigned char *)"?" : 7270Sstevel@tonic-gate (unsigned char *)"/"; 7280Sstevel@tonic-gate c = *vglobp++; 7290Sstevel@tonic-gate goto nocount; 7300Sstevel@tonic-gate 7310Sstevel@tonic-gate /* 7320Sstevel@tonic-gate * ' Return to line specified by following mark, 7330Sstevel@tonic-gate * first white position on line. 7340Sstevel@tonic-gate * 7350Sstevel@tonic-gate * ` Return to marked line at remembered column. 7360Sstevel@tonic-gate */ 7370Sstevel@tonic-gate case '\'': 7380Sstevel@tonic-gate case '`': 7390Sstevel@tonic-gate d = c; 7400Sstevel@tonic-gate c = getesc(); 7410Sstevel@tonic-gate if (c == 0) 7420Sstevel@tonic-gate return; 7430Sstevel@tonic-gate c = markreg(c); 7440Sstevel@tonic-gate forbid(c == 0); 7450Sstevel@tonic-gate wdot = getmark(c); 7460Sstevel@tonic-gate forbid(wdot == NOLINE); 7470Sstevel@tonic-gate forbid(Xhadcnt); 7480Sstevel@tonic-gate vmoving = 0; 7490Sstevel@tonic-gate wcursor = d == '`' ? ncols[c - 'a'] : 0; 7500Sstevel@tonic-gate if (opf == vmove && (wdot != dot || 7510Sstevel@tonic-gate (d == '`' && wcursor != cursor))) 7520Sstevel@tonic-gate markDOT(); 7530Sstevel@tonic-gate if (wcursor) { 7540Sstevel@tonic-gate vsave(); 7550Sstevel@tonic-gate getline(*wdot); 7560Sstevel@tonic-gate if (wcursor > strend(linebuf)) 7570Sstevel@tonic-gate wcursor = 0; 7580Sstevel@tonic-gate else { 7590Sstevel@tonic-gate cnt = wcursor - linebuf; 7600Sstevel@tonic-gate /*CSTYLED*/ 7610Sstevel@tonic-gate for (wcursor = linebuf; wcursor - linebuf < cnt; ) 7620Sstevel@tonic-gate wcursor = nextchr(wcursor); 7630Sstevel@tonic-gate if (wcursor - linebuf > cnt) 7640Sstevel@tonic-gate wcursor = lastchr(linebuf, wcursor); 7650Sstevel@tonic-gate } 7660Sstevel@tonic-gate getDOT(); 7670Sstevel@tonic-gate } 7680Sstevel@tonic-gate if (ospeed > B300) 7690Sstevel@tonic-gate hold |= HOLDWIG; 7700Sstevel@tonic-gate break; 7710Sstevel@tonic-gate 7720Sstevel@tonic-gate /* 7730Sstevel@tonic-gate * G Goto count'th line, or last line if no count 7740Sstevel@tonic-gate * given. 7750Sstevel@tonic-gate */ 7760Sstevel@tonic-gate case 'G': 7770Sstevel@tonic-gate if (!Xhadcnt) 7780Sstevel@tonic-gate cnt = lineDOL(); 7790Sstevel@tonic-gate wdot = zero + cnt; 7800Sstevel@tonic-gate forbid(wdot < one || wdot > dol); 7810Sstevel@tonic-gate if (opf == vmove) 7820Sstevel@tonic-gate markit(wdot); 7830Sstevel@tonic-gate vmoving = 0; 7840Sstevel@tonic-gate wcursor = 0; 7850Sstevel@tonic-gate break; 7860Sstevel@tonic-gate 7870Sstevel@tonic-gate /* 7880Sstevel@tonic-gate * / Scan forward for following re. 7890Sstevel@tonic-gate * ? Scan backward for following re. 7900Sstevel@tonic-gate */ 7910Sstevel@tonic-gate case '/': 7920Sstevel@tonic-gate case '?': 7930Sstevel@tonic-gate forbid(Xhadcnt); 7940Sstevel@tonic-gate vsave(); 7950Sstevel@tonic-gate oc = c; 7960Sstevel@tonic-gate ocurs = cursor; 7970Sstevel@tonic-gate odot = dot; 7980Sstevel@tonic-gate wcursor = 0; 7990Sstevel@tonic-gate if (readecho(c)) 8000Sstevel@tonic-gate return; 8010Sstevel@tonic-gate if (!vglobp) 8020Sstevel@tonic-gate vscandir[0] = genbuf[0]; 8030Sstevel@tonic-gate oglobp = globp; CP(vutmp, genbuf); globp = vutmp; 8040Sstevel@tonic-gate d = peekc; 8050Sstevel@tonic-gate fromsemi: 8060Sstevel@tonic-gate ungetchar(0); 8070Sstevel@tonic-gate fixech(); 8080Sstevel@tonic-gate CATCH 8090Sstevel@tonic-gate #ifndef CBREAK 8100Sstevel@tonic-gate /* 8110Sstevel@tonic-gate * Lose typeahead (ick). 8120Sstevel@tonic-gate */ 8130Sstevel@tonic-gate vcook(); 8140Sstevel@tonic-gate #endif 8150Sstevel@tonic-gate addr = address(cursor); 8160Sstevel@tonic-gate #ifndef CBREAK 8170Sstevel@tonic-gate vraw(); 8180Sstevel@tonic-gate #endif 8190Sstevel@tonic-gate ONERR 8200Sstevel@tonic-gate #ifndef CBREAK 8210Sstevel@tonic-gate vraw(); 8220Sstevel@tonic-gate #endif 8230Sstevel@tonic-gate slerr: 8240Sstevel@tonic-gate globp = oglobp; 8250Sstevel@tonic-gate dot = odot; 8260Sstevel@tonic-gate cursor = ocurs; 8270Sstevel@tonic-gate ungetchar(d); 8280Sstevel@tonic-gate splitw = 0; 8290Sstevel@tonic-gate vclean(); 8300Sstevel@tonic-gate vjumpto(dot, ocurs, 0); 8310Sstevel@tonic-gate return; 8320Sstevel@tonic-gate ENDCATCH 8330Sstevel@tonic-gate if (globp == 0) 8340Sstevel@tonic-gate globp = (unsigned char *)""; 8350Sstevel@tonic-gate else if (peekc) 8360Sstevel@tonic-gate --globp; 8370Sstevel@tonic-gate if (*globp == ';') { 8380Sstevel@tonic-gate /* /foo/;/bar/ */ 8390Sstevel@tonic-gate globp++; 8400Sstevel@tonic-gate dot = addr; 8410Sstevel@tonic-gate cursor = (unsigned char *)loc1; 8420Sstevel@tonic-gate goto fromsemi; 8430Sstevel@tonic-gate } 8440Sstevel@tonic-gate dot = odot; 8450Sstevel@tonic-gate ungetchar(d); 8460Sstevel@tonic-gate c = 0; 8470Sstevel@tonic-gate if (*globp == 'z') 8480Sstevel@tonic-gate globp++, c = '\n'; 8490Sstevel@tonic-gate if (any(*globp, "^+-.")) 8500Sstevel@tonic-gate c = *globp++; 8510Sstevel@tonic-gate i = 0; 8520Sstevel@tonic-gate while (isdigit(*globp)) 8530Sstevel@tonic-gate i = i * 10 + *globp++ - '0'; 8540Sstevel@tonic-gate if (any(*globp, "^+-.")) 8550Sstevel@tonic-gate c = *globp++; 8560Sstevel@tonic-gate if (*globp) { 8570Sstevel@tonic-gate /* random junk after the pattern */ 858*802Scf46844 (void) beep(); 8590Sstevel@tonic-gate goto slerr; 8600Sstevel@tonic-gate } 8610Sstevel@tonic-gate globp = oglobp; 8620Sstevel@tonic-gate splitw = 0; 8630Sstevel@tonic-gate vmoving = 0; 8640Sstevel@tonic-gate wcursor = (unsigned char *)loc1; 8650Sstevel@tonic-gate if (i != 0) 8660Sstevel@tonic-gate vsetsiz(i); 8670Sstevel@tonic-gate if (opf == vmove) { 8680Sstevel@tonic-gate if (state == ONEOPEN || state == HARDOPEN) 8690Sstevel@tonic-gate outline = destline = WBOT; 8700Sstevel@tonic-gate if (addr != dot || (unsigned char *)loc1 != cursor) 8710Sstevel@tonic-gate markDOT(); 8720Sstevel@tonic-gate if (loc1 > (char *)linebuf && *loc1 == 0) 8730Sstevel@tonic-gate loc1 = (char *)lastchr(linebuf, loc1); 8740Sstevel@tonic-gate if (c) 875*802Scf46844 vjumpto(addr, (unsigned char *)loc1, c); 8760Sstevel@tonic-gate else { 8770Sstevel@tonic-gate vmoving = 0; 8780Sstevel@tonic-gate if (loc1) { 8790Sstevel@tonic-gate vmoving++; 8800Sstevel@tonic-gate vmovcol = column(loc1); 8810Sstevel@tonic-gate } 8820Sstevel@tonic-gate getDOT(); 8830Sstevel@tonic-gate if (state == CRTOPEN && addr != dot) 8840Sstevel@tonic-gate vup1(); 8850Sstevel@tonic-gate vupdown(addr - dot, NOSTR); 8860Sstevel@tonic-gate } 8870Sstevel@tonic-gate if (oc == '/') { /* forward search */ 8880Sstevel@tonic-gate if (dot < odot || 8890Sstevel@tonic-gate (dot == odot && cursor <= ocurs)) 8900Sstevel@tonic-gate warnf(value(vi_TERSE) ? 8910Sstevel@tonic-gate gettext("Search wrapped BOTTOM") : 8920Sstevel@tonic-gate gettext("Search wrapped around BOTTOM of buffer")); 8930Sstevel@tonic-gate } else { /* backward search */ 8940Sstevel@tonic-gate if (dot > odot || 8950Sstevel@tonic-gate (dot == odot && cursor >= ocurs)) 8960Sstevel@tonic-gate warnf(value(vi_TERSE) ? 8970Sstevel@tonic-gate gettext("Search wrapped TOP") : 8980Sstevel@tonic-gate gettext("Search wrapped around TOP of buffer")); 8990Sstevel@tonic-gate } 9000Sstevel@tonic-gate return; 9010Sstevel@tonic-gate } 9020Sstevel@tonic-gate lastcp[-1] = 'n'; 9030Sstevel@tonic-gate getDOT(); 9040Sstevel@tonic-gate wdot = addr; 9050Sstevel@tonic-gate break; 9060Sstevel@tonic-gate } 9070Sstevel@tonic-gate /* 9080Sstevel@tonic-gate * Apply. 9090Sstevel@tonic-gate */ 9100Sstevel@tonic-gate if (vreg && wdot == 0) 9110Sstevel@tonic-gate wdot = dot; 9120Sstevel@tonic-gate (*opf)(c); 9130Sstevel@tonic-gate wdot = NOLINE; 9140Sstevel@tonic-gate } 9150Sstevel@tonic-gate 9160Sstevel@tonic-gate static void 9170Sstevel@tonic-gate lfixol() 9180Sstevel@tonic-gate { 9190Sstevel@tonic-gate unsigned char *savevglobp; 9200Sstevel@tonic-gate int savesplit; 9210Sstevel@tonic-gate 9220Sstevel@tonic-gate if (Outchar == vputchar) 9230Sstevel@tonic-gate return; 9240Sstevel@tonic-gate 9250Sstevel@tonic-gate /* Show messages */ 9260Sstevel@tonic-gate putnl(); 9270Sstevel@tonic-gate if (inopen > 0 && clr_eol) 9280Sstevel@tonic-gate vclreol(); 9290Sstevel@tonic-gate if (enter_standout_mode && exit_bold) 930*802Scf46844 putpad((unsigned char *)enter_standout_mode); 9310Sstevel@tonic-gate lprintf(gettext("[Hit return to continue] "), 0); 9320Sstevel@tonic-gate if (enter_standout_mode && exit_bold) 933*802Scf46844 putpad((unsigned char *)exit_bold); 9340Sstevel@tonic-gate 9350Sstevel@tonic-gate /* Get key input for confirmation */ 9360Sstevel@tonic-gate savevglobp = vglobp; 9370Sstevel@tonic-gate vglobp = 0; /* force typed input */ 9380Sstevel@tonic-gate getkey(); 9390Sstevel@tonic-gate vglobp = savevglobp; 9400Sstevel@tonic-gate 9410Sstevel@tonic-gate /* reset output function */ 9420Sstevel@tonic-gate Outchar = vputchar; 9430Sstevel@tonic-gate 9440Sstevel@tonic-gate /* Clean up screen */ 9450Sstevel@tonic-gate savesplit = splitw; 9460Sstevel@tonic-gate splitw = 0; 9470Sstevel@tonic-gate vclear(); 9480Sstevel@tonic-gate vdirty(0, WLINES); 9490Sstevel@tonic-gate vredraw(WTOP); 9500Sstevel@tonic-gate splitw = savesplit; 9510Sstevel@tonic-gate } 9520Sstevel@tonic-gate 953*802Scf46844 void 954*802Scf46844 warnf(char *str, char *cp) 9550Sstevel@tonic-gate { 9560Sstevel@tonic-gate int saveline, savecol, savesplit; 9570Sstevel@tonic-gate 9580Sstevel@tonic-gate saveline = outline; 9590Sstevel@tonic-gate savecol = outcol; 9600Sstevel@tonic-gate savesplit = splitw; 9610Sstevel@tonic-gate splitw = 1; 9620Sstevel@tonic-gate vgoto(WECHO, 0); 9630Sstevel@tonic-gate if (!enter_standout_mode || !exit_bold) 9640Sstevel@tonic-gate dingdong(); 9650Sstevel@tonic-gate if (clr_eol) 9660Sstevel@tonic-gate vclreol(); 9670Sstevel@tonic-gate if (enter_standout_mode && exit_bold) 968*802Scf46844 putpad((unsigned char *)enter_standout_mode); 9690Sstevel@tonic-gate lprintf(str, cp); 9700Sstevel@tonic-gate if (enter_standout_mode && exit_bold) 971*802Scf46844 putpad((unsigned char *)exit_bold); 9720Sstevel@tonic-gate lfixol(); 9730Sstevel@tonic-gate vgoto(saveline, savecol); 9740Sstevel@tonic-gate splitw = savesplit; 9750Sstevel@tonic-gate } 9760Sstevel@tonic-gate 9770Sstevel@tonic-gate /* #ifdef PTR_ADDRESSES */ 9780Sstevel@tonic-gate /* 9790Sstevel@tonic-gate * read in a row or column address 9800Sstevel@tonic-gate * 9810Sstevel@tonic-gate */ 9820Sstevel@tonic-gate static int 9830Sstevel@tonic-gate get_addr() 9840Sstevel@tonic-gate { 985*802Scf46844 short c; 986*802Scf46844 short next; 9870Sstevel@tonic-gate 9880Sstevel@tonic-gate c = getkey(); 9890Sstevel@tonic-gate next = 0; 9900Sstevel@tonic-gate switch (c) { 9910Sstevel@tonic-gate case CTRL('A'): 9920Sstevel@tonic-gate next = 96; 9930Sstevel@tonic-gate c = getkey(); 9940Sstevel@tonic-gate break; 9950Sstevel@tonic-gate 9960Sstevel@tonic-gate case CTRL('B'): 9970Sstevel@tonic-gate next = 192; 9980Sstevel@tonic-gate c = getkey(); 9990Sstevel@tonic-gate break; 10000Sstevel@tonic-gate } 10010Sstevel@tonic-gate if (c < ' ') 10020Sstevel@tonic-gate return (-1); 10030Sstevel@tonic-gate return (next + c - ' '); 10040Sstevel@tonic-gate } 10050Sstevel@tonic-gate /* #endif PTR_ADDRESSES */ 10060Sstevel@tonic-gate 10070Sstevel@tonic-gate /* 10080Sstevel@tonic-gate * Find single character c, in direction dir from cursor. 10090Sstevel@tonic-gate */ 1010*802Scf46844 int 1011*802Scf46844 find(wchar_t c) 10120Sstevel@tonic-gate { 10130Sstevel@tonic-gate 10140Sstevel@tonic-gate wchar_t wchar; 10150Sstevel@tonic-gate int length; 10160Sstevel@tonic-gate for (;;) { 10170Sstevel@tonic-gate if (edge()) 10180Sstevel@tonic-gate return (0); 10190Sstevel@tonic-gate if (dir == 1) 10200Sstevel@tonic-gate wcursor = nextchr(wcursor); 10210Sstevel@tonic-gate else 10220Sstevel@tonic-gate wcursor = lastchr(linebuf, wcursor); 10230Sstevel@tonic-gate if ((length = mbtowc(&wchar, (char *)wcursor, 10240Sstevel@tonic-gate MULTI_BYTE_MAX)) > 0 && wchar == c) 10250Sstevel@tonic-gate return (1); 10260Sstevel@tonic-gate } 10270Sstevel@tonic-gate } 10280Sstevel@tonic-gate 10290Sstevel@tonic-gate /* 10300Sstevel@tonic-gate * Do a word motion with operator op, and cnt more words 10310Sstevel@tonic-gate * to go after this. 10320Sstevel@tonic-gate */ 1033*802Scf46844 int 1034*802Scf46844 word(int (*op)(), int cnt) 10350Sstevel@tonic-gate { 1036*802Scf46844 int which; 1037*802Scf46844 unsigned char *iwc; 1038*802Scf46844 line *iwdot = wdot; 10390Sstevel@tonic-gate wchar_t wchar; 10400Sstevel@tonic-gate int length; 10410Sstevel@tonic-gate 10420Sstevel@tonic-gate if (dir == 1) { 10430Sstevel@tonic-gate iwc = wcursor; 10440Sstevel@tonic-gate which = wordch(wcursor); 10450Sstevel@tonic-gate while (wordof(which, wcursor)) { 10460Sstevel@tonic-gate length = mbtowc(&wchar, (char *)wcursor, 10470Sstevel@tonic-gate MULTI_BYTE_MAX); 10480Sstevel@tonic-gate if (length <= 0) 10490Sstevel@tonic-gate length = 1; 10500Sstevel@tonic-gate if (cnt == 1 && op != vmove && wcursor[length] == 0) { 10510Sstevel@tonic-gate wcursor += length; 10520Sstevel@tonic-gate break; 10530Sstevel@tonic-gate } 10540Sstevel@tonic-gate if (!lnext()) 10550Sstevel@tonic-gate return (0); 10560Sstevel@tonic-gate if (wcursor == linebuf) 10570Sstevel@tonic-gate break; 10580Sstevel@tonic-gate } 10590Sstevel@tonic-gate /* Unless last segment of a change skip blanks */ 1060*802Scf46844 if (op != (int (*)())vchange || cnt > 1) 10610Sstevel@tonic-gate while (!margin() && blank()) { 10620Sstevel@tonic-gate if (!lnext()) 10630Sstevel@tonic-gate return (0); 10640Sstevel@tonic-gate } 10650Sstevel@tonic-gate else 10660Sstevel@tonic-gate if (wcursor == iwc && iwdot == wdot && *iwc) 10670Sstevel@tonic-gate wcursor = nextchr(wcursor); 10680Sstevel@tonic-gate if (op == vmove && margin()) { 10690Sstevel@tonic-gate wcursor = lastchr(linebuf, wcursor); 10700Sstevel@tonic-gate #ifdef XPG4 10710Sstevel@tonic-gate if (wcursor < linebuf) { 10720Sstevel@tonic-gate wcursor = linebuf; 10730Sstevel@tonic-gate } 10740Sstevel@tonic-gate #endif /* XPG4 */ 10750Sstevel@tonic-gate } 10760Sstevel@tonic-gate } else { 10770Sstevel@tonic-gate if (!lnext()) 10780Sstevel@tonic-gate return (0); 10790Sstevel@tonic-gate while (blank()) 10800Sstevel@tonic-gate if (!lnext()) 10810Sstevel@tonic-gate return (0); 10820Sstevel@tonic-gate if (!margin()) { 10830Sstevel@tonic-gate which = wordch(wcursor); 10840Sstevel@tonic-gate while (!margin() && wordof(which, wcursor)) 10850Sstevel@tonic-gate wcursor = lastchr(linebuf, wcursor); 10860Sstevel@tonic-gate } 10870Sstevel@tonic-gate #ifdef PRESUNEUC 10880Sstevel@tonic-gate if (wcursor < linebuf || !wordof(which, wcursor)) 10890Sstevel@tonic-gate wcursor = nextchr(wcursor); 10900Sstevel@tonic-gate #else 10910Sstevel@tonic-gate if (wcursor < linebuf) 10920Sstevel@tonic-gate wcursor++; 10930Sstevel@tonic-gate else if (!wordof(which, wcursor)) 10940Sstevel@tonic-gate wcursor = nextchr(wcursor); 10950Sstevel@tonic-gate #endif /* PRESUNEUC */ 10960Sstevel@tonic-gate } 10970Sstevel@tonic-gate return (1); 10980Sstevel@tonic-gate } 10990Sstevel@tonic-gate 11000Sstevel@tonic-gate /* 11010Sstevel@tonic-gate * To end of word, with operator op and cnt more motions 11020Sstevel@tonic-gate * remaining after this. 11030Sstevel@tonic-gate */ 1104*802Scf46844 int 1105*802Scf46844 eend(int (*op)()) 11060Sstevel@tonic-gate { 1107*802Scf46844 int which; 11080Sstevel@tonic-gate 11090Sstevel@tonic-gate if (!lnext()) 11100Sstevel@tonic-gate return (0); 11110Sstevel@tonic-gate while (blank()) 11120Sstevel@tonic-gate if (!lnext()) 11130Sstevel@tonic-gate return (0); 11140Sstevel@tonic-gate which = wordch(wcursor); 11150Sstevel@tonic-gate while (wordof(which, wcursor)) { 11160Sstevel@tonic-gate if (wcursor[1] == 0) { 11170Sstevel@tonic-gate wcursor = nextchr(wcursor); 11180Sstevel@tonic-gate break; 11190Sstevel@tonic-gate } 11200Sstevel@tonic-gate if (!lnext()) 11210Sstevel@tonic-gate return (0); 11220Sstevel@tonic-gate } 11230Sstevel@tonic-gate if (op == vyankit) 11240Sstevel@tonic-gate wcursor = lastchr(linebuf, wcursor) + 1; 1125*802Scf46844 else if (op != (int (*)())vchange && op != (int (*)())vdelete && 1126*802Scf46844 wcursor > linebuf) 11270Sstevel@tonic-gate wcursor = lastchr(linebuf, wcursor); 11280Sstevel@tonic-gate return (1); 11290Sstevel@tonic-gate } 11300Sstevel@tonic-gate 11310Sstevel@tonic-gate /* 11320Sstevel@tonic-gate * Wordof tells whether the character at *wc is in a word of 11330Sstevel@tonic-gate * kind which (blank/nonblank words are 0, conservative words 1). 11340Sstevel@tonic-gate */ 1135*802Scf46844 int 1136*802Scf46844 wordof(unsigned char which, unsigned char *wc) 11370Sstevel@tonic-gate { 11380Sstevel@tonic-gate #ifdef PRESUNEUC 11390Sstevel@tonic-gate 11400Sstevel@tonic-gate if (isspace(*wc)) 11410Sstevel@tonic-gate #else 11420Sstevel@tonic-gate wchar_t z; 11430Sstevel@tonic-gate 11440Sstevel@tonic-gate (void) mbtowc(&z, (char *)wc, MB_LEN_MAX); 11450Sstevel@tonic-gate if (iswspace(z)) 11460Sstevel@tonic-gate #endif /* PRESUNEUC */ 11470Sstevel@tonic-gate return (0); 11480Sstevel@tonic-gate return (!wdkind || wordch(wc) == which); 11490Sstevel@tonic-gate } 11500Sstevel@tonic-gate 11510Sstevel@tonic-gate /* 11520Sstevel@tonic-gate * Wordch tells whether character at *wc is a word character 11530Sstevel@tonic-gate * i.e. an alfa, digit, or underscore. 11540Sstevel@tonic-gate */ 11550Sstevel@tonic-gate #ifdef PRESUNEUC 11560Sstevel@tonic-gate #define SS2 0216 11570Sstevel@tonic-gate #define SS3 0217 11580Sstevel@tonic-gate #endif /* PRESUNEUC */ 11590Sstevel@tonic-gate 1160*802Scf46844 int 1161*802Scf46844 wordch(unsigned char *wc) 11620Sstevel@tonic-gate { 1163*802Scf46844 int length; 11640Sstevel@tonic-gate wchar_t c; 11650Sstevel@tonic-gate 11660Sstevel@tonic-gate length = mbtowc(&c, (char *)wc, MULTI_BYTE_MAX); 11670Sstevel@tonic-gate if (length <= 0) 11680Sstevel@tonic-gate return (0); 11690Sstevel@tonic-gate if (length > 1) 11700Sstevel@tonic-gate #ifndef PRESUNEUC 11710Sstevel@tonic-gate if (wdwc) 11720Sstevel@tonic-gate return (*wdwc)(c); 11730Sstevel@tonic-gate else 11740Sstevel@tonic-gate #endif /* PRESUNEUC */ 11750Sstevel@tonic-gate return (length); 11760Sstevel@tonic-gate #ifndef PRESUNEUC 11770Sstevel@tonic-gate return (isalpha(*wc) || isdigit(*wc) || *wc == '_'); 11780Sstevel@tonic-gate #else 11790Sstevel@tonic-gate return (isalpha(c) || isdigit(c) || c == '_'); 11800Sstevel@tonic-gate #endif /* PRESUNEUC */ 11810Sstevel@tonic-gate } 11820Sstevel@tonic-gate 11830Sstevel@tonic-gate /* 11840Sstevel@tonic-gate * Edge tells when we hit the last character in the current line. 11850Sstevel@tonic-gate */ 1186*802Scf46844 int 1187*802Scf46844 edge(void) 11880Sstevel@tonic-gate { 11890Sstevel@tonic-gate 11900Sstevel@tonic-gate if (linebuf[0] == 0) 11910Sstevel@tonic-gate return (1); 11920Sstevel@tonic-gate if (dir == 1) 11930Sstevel@tonic-gate return (*(nextchr(wcursor)) == 0); 11940Sstevel@tonic-gate else 11950Sstevel@tonic-gate return (wcursor == linebuf); 11960Sstevel@tonic-gate } 11970Sstevel@tonic-gate 11980Sstevel@tonic-gate /* 11990Sstevel@tonic-gate * Margin tells us when we have fallen off the end of the line. 12000Sstevel@tonic-gate */ 1201*802Scf46844 int 1202*802Scf46844 margin(void) 12030Sstevel@tonic-gate { 12040Sstevel@tonic-gate 12050Sstevel@tonic-gate return (wcursor < linebuf || wcursor[0] == 0); 12060Sstevel@tonic-gate } 12070Sstevel@tonic-gate #ifndef PRESUNEUC 12080Sstevel@tonic-gate 12090Sstevel@tonic-gate /* 12100Sstevel@tonic-gate * Blank tells if the cursor is currently on a TAB, RETURN, 12110Sstevel@tonic-gate * NEWLINE, FORMFEED, bertical tab, or SPACE character from EUC 12120Sstevel@tonic-gate * primary and supplementary codesets. 12130Sstevel@tonic-gate */ 1214*802Scf46844 int 1215*802Scf46844 blank(void) 12160Sstevel@tonic-gate { 12170Sstevel@tonic-gate wchar_t z; 12180Sstevel@tonic-gate 12190Sstevel@tonic-gate (void) mbtowc(&z, (char *)wcursor, MB_CUR_MAX); 12200Sstevel@tonic-gate return (iswspace((int)z)); 12210Sstevel@tonic-gate } 12220Sstevel@tonic-gate #endif /* PRESUNEUC */ 1223