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 /* Copyright (c) 1981 Regents of the University of California */ 320Sstevel@tonic-gate 33*802Scf46844 #pragma ident "%Z%%M% %I% %E% SMI" 340Sstevel@tonic-gate 350Sstevel@tonic-gate #include "ex.h" 360Sstevel@tonic-gate #include "ex_tty.h" 370Sstevel@tonic-gate 380Sstevel@tonic-gate /* 390Sstevel@tonic-gate * Input routines for command mode. 400Sstevel@tonic-gate * Since we translate the end of reads into the implied ^D's 410Sstevel@tonic-gate * we have different flavors of routines which do/don't return such. 420Sstevel@tonic-gate */ 430Sstevel@tonic-gate static bool junkbs; 440Sstevel@tonic-gate short lastc = '\n'; 450Sstevel@tonic-gate 46*802Scf46844 void 47*802Scf46844 ignchar(void) 480Sstevel@tonic-gate { 490Sstevel@tonic-gate (void)getchar(); 500Sstevel@tonic-gate } 510Sstevel@tonic-gate 52*802Scf46844 int 53*802Scf46844 getchar(void) 540Sstevel@tonic-gate { 55*802Scf46844 int c; 560Sstevel@tonic-gate 570Sstevel@tonic-gate do 580Sstevel@tonic-gate c = getcd(); 590Sstevel@tonic-gate while (!globp && c == CTRL('d')); 600Sstevel@tonic-gate return (c); 610Sstevel@tonic-gate } 620Sstevel@tonic-gate 63*802Scf46844 int 64*802Scf46844 getcd(void) 650Sstevel@tonic-gate { 66*802Scf46844 int c; 670Sstevel@tonic-gate extern short slevel; 680Sstevel@tonic-gate 690Sstevel@tonic-gate again: 700Sstevel@tonic-gate c = getach(); 710Sstevel@tonic-gate if (c == EOF) 720Sstevel@tonic-gate return (c); 730Sstevel@tonic-gate if (!inopen && slevel==0) 740Sstevel@tonic-gate if (!globp && c == CTRL('d')) 750Sstevel@tonic-gate setlastchar('\n'); 760Sstevel@tonic-gate else if (junk(c)) { 770Sstevel@tonic-gate checkjunk(c); 780Sstevel@tonic-gate goto again; 790Sstevel@tonic-gate } 800Sstevel@tonic-gate return (c); 810Sstevel@tonic-gate } 820Sstevel@tonic-gate 83*802Scf46844 int 84*802Scf46844 peekchar(void) 850Sstevel@tonic-gate { 860Sstevel@tonic-gate 870Sstevel@tonic-gate if (peekc == 0) 880Sstevel@tonic-gate peekc = getchar(); 890Sstevel@tonic-gate return (peekc); 900Sstevel@tonic-gate } 910Sstevel@tonic-gate 92*802Scf46844 int 93*802Scf46844 peekcd(void) 940Sstevel@tonic-gate { 950Sstevel@tonic-gate if (peekc == 0) 960Sstevel@tonic-gate peekc = getcd(); 970Sstevel@tonic-gate return (peekc); 980Sstevel@tonic-gate } 990Sstevel@tonic-gate 1000Sstevel@tonic-gate int verbose; 101*802Scf46844 int 102*802Scf46844 getach(void) 1030Sstevel@tonic-gate { 104*802Scf46844 int c, i, prev; 1050Sstevel@tonic-gate static unsigned char inputline[128]; 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate c = peekc; 1080Sstevel@tonic-gate if (c != 0) { 1090Sstevel@tonic-gate peekc = 0; 1100Sstevel@tonic-gate return (c); 1110Sstevel@tonic-gate } 1120Sstevel@tonic-gate if (globp) { 1130Sstevel@tonic-gate if (*globp) 1140Sstevel@tonic-gate return (*globp++); 1150Sstevel@tonic-gate globp = 0; 1160Sstevel@tonic-gate return (lastc = EOF); 1170Sstevel@tonic-gate } 1180Sstevel@tonic-gate top: 1190Sstevel@tonic-gate if (input) { 1200Sstevel@tonic-gate if(c = *input++) 1210Sstevel@tonic-gate return (lastc = c); 1220Sstevel@tonic-gate input = 0; 1230Sstevel@tonic-gate } 1240Sstevel@tonic-gate flush(); 1250Sstevel@tonic-gate if (intty) { 1260Sstevel@tonic-gate c = read(0, inputline, sizeof inputline - 4); 1270Sstevel@tonic-gate if (c < 0) 1280Sstevel@tonic-gate return (lastc = EOF); 1290Sstevel@tonic-gate if (c == 0 || inputline[c-1] != '\n') 1300Sstevel@tonic-gate inputline[c++] = CTRL('d'); 1310Sstevel@tonic-gate if (inputline[c-1] == '\n') 1320Sstevel@tonic-gate noteinp(); 1330Sstevel@tonic-gate prev = 0; 1340Sstevel@tonic-gate /* remove nulls from input buffer */ 1350Sstevel@tonic-gate for (i = 0; i < c; i++) 1360Sstevel@tonic-gate if(inputline[i] != 0) 1370Sstevel@tonic-gate inputline[prev++] = inputline[i]; 1380Sstevel@tonic-gate inputline[prev] = 0; 1390Sstevel@tonic-gate input = inputline; 1400Sstevel@tonic-gate goto top; 1410Sstevel@tonic-gate } 1420Sstevel@tonic-gate if (read(0, inputline, 1) != 1) 1430Sstevel@tonic-gate lastc = EOF; 1440Sstevel@tonic-gate else { 1450Sstevel@tonic-gate lastc = inputline[0]; 1460Sstevel@tonic-gate if (verbose) 1470Sstevel@tonic-gate write(2, inputline, 1); 1480Sstevel@tonic-gate } 1490Sstevel@tonic-gate return (lastc); 1500Sstevel@tonic-gate } 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate /* 1530Sstevel@tonic-gate * Input routine for insert/append/change in command mode. 1540Sstevel@tonic-gate * Most work here is in handling autoindent. 1550Sstevel@tonic-gate */ 1560Sstevel@tonic-gate static short lastin; 1570Sstevel@tonic-gate 158*802Scf46844 int 159*802Scf46844 gettty(void) 1600Sstevel@tonic-gate { 161*802Scf46844 int c = 0; 162*802Scf46844 unsigned char *cp = genbuf; 1630Sstevel@tonic-gate unsigned char hadup = 0; 1640Sstevel@tonic-gate extern int (*Pline)(); 1650Sstevel@tonic-gate int offset = Pline == numbline ? 8 : 0; 1660Sstevel@tonic-gate int ch; 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate if (intty && !inglobal) { 1690Sstevel@tonic-gate if (offset) { 1700Sstevel@tonic-gate holdcm = 1; 171*802Scf46844 viprintf(" %4d ", lineDOT() + 1); 1720Sstevel@tonic-gate flush(); 1730Sstevel@tonic-gate holdcm = 0; 1740Sstevel@tonic-gate } 1750Sstevel@tonic-gate if (value(vi_AUTOINDENT) ^ aiflag) { 1760Sstevel@tonic-gate holdcm = 1; 1770Sstevel@tonic-gate if (value(vi_LISP)) 1780Sstevel@tonic-gate lastin = lindent(dot + 1); 1790Sstevel@tonic-gate gotab(lastin + offset); 1800Sstevel@tonic-gate while ((c = getcd()) == CTRL('d')) { 1810Sstevel@tonic-gate if (lastin == 0 && isatty(0) == -1) { 1820Sstevel@tonic-gate holdcm = 0; 1830Sstevel@tonic-gate return (EOF); 1840Sstevel@tonic-gate } 1850Sstevel@tonic-gate lastin = backtab(lastin); 1860Sstevel@tonic-gate gotab(lastin + offset); 1870Sstevel@tonic-gate } 1880Sstevel@tonic-gate switch (c) { 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate case '^': 1910Sstevel@tonic-gate case '0': 1920Sstevel@tonic-gate ch = getcd(); 1930Sstevel@tonic-gate if (ch == CTRL('d')) { 1940Sstevel@tonic-gate if (c == '0') 1950Sstevel@tonic-gate lastin = 0; 1960Sstevel@tonic-gate if (!over_strike) { 1970Sstevel@tonic-gate putchar((int)('\b' | QUOTE)); 1980Sstevel@tonic-gate putchar((int)(' ' | QUOTE)); 1990Sstevel@tonic-gate putchar((int)('\b' | QUOTE)); 2000Sstevel@tonic-gate } 2010Sstevel@tonic-gate gotab(offset); 2020Sstevel@tonic-gate hadup = 1; 2030Sstevel@tonic-gate c = getchar(); 2040Sstevel@tonic-gate } else 2050Sstevel@tonic-gate ungetchar(ch); 2060Sstevel@tonic-gate break; 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate case '.': 2090Sstevel@tonic-gate if (peekchar() == '\n') { 2100Sstevel@tonic-gate ignchar(); 2110Sstevel@tonic-gate noteinp(); 2120Sstevel@tonic-gate holdcm = 0; 2130Sstevel@tonic-gate return (EOF); 2140Sstevel@tonic-gate } 2150Sstevel@tonic-gate break; 2160Sstevel@tonic-gate 2170Sstevel@tonic-gate case '\n': 2180Sstevel@tonic-gate hadup = 1; 2190Sstevel@tonic-gate break; 2200Sstevel@tonic-gate } 2210Sstevel@tonic-gate } 2220Sstevel@tonic-gate flush(); 2230Sstevel@tonic-gate holdcm = 0; 2240Sstevel@tonic-gate } 2250Sstevel@tonic-gate if (c == 0) 2260Sstevel@tonic-gate c = getchar(); 2270Sstevel@tonic-gate while (c != EOF && c != '\n') { 2280Sstevel@tonic-gate if (cp > &genbuf[LBSIZE - 2]) 2290Sstevel@tonic-gate error(gettext("Input line too long")); 2300Sstevel@tonic-gate *cp++ = c; 2310Sstevel@tonic-gate c = getchar(); 2320Sstevel@tonic-gate } 2330Sstevel@tonic-gate if (c == EOF) { 2340Sstevel@tonic-gate if (inglobal) 2350Sstevel@tonic-gate ungetchar(EOF); 2360Sstevel@tonic-gate return (EOF); 2370Sstevel@tonic-gate } 2380Sstevel@tonic-gate *cp = 0; 2390Sstevel@tonic-gate cp = linebuf; 2400Sstevel@tonic-gate if ((value(vi_AUTOINDENT) ^ aiflag) && hadup == 0 && intty && !inglobal) { 2410Sstevel@tonic-gate lastin = c = smunch(lastin, genbuf); 2420Sstevel@tonic-gate for (c = lastin; c >= value(vi_TABSTOP); c -= value(vi_TABSTOP)) 2430Sstevel@tonic-gate *cp++ = '\t'; 2440Sstevel@tonic-gate for (; c > 0; c--) 2450Sstevel@tonic-gate *cp++ = ' '; 2460Sstevel@tonic-gate } 2470Sstevel@tonic-gate CP(cp, genbuf); 2480Sstevel@tonic-gate if (linebuf[0] == '.' && linebuf[1] == 0) 2490Sstevel@tonic-gate return (EOF); 2500Sstevel@tonic-gate return (0); 2510Sstevel@tonic-gate } 2520Sstevel@tonic-gate 2530Sstevel@tonic-gate /* 2540Sstevel@tonic-gate * Crunch the indent. 2550Sstevel@tonic-gate * Hard thing here is that in command mode some of the indent 2560Sstevel@tonic-gate * is only implicit, so we must seed the column counter. 2570Sstevel@tonic-gate * This should really be done differently so as to use the whitecnt routine 2580Sstevel@tonic-gate * and also to hack indenting for LISP. 2590Sstevel@tonic-gate */ 260*802Scf46844 int 261*802Scf46844 smunch(int col, unsigned char *ocp) 2620Sstevel@tonic-gate { 263*802Scf46844 unsigned char *cp; 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate cp = ocp; 2660Sstevel@tonic-gate for (;;) 2670Sstevel@tonic-gate switch (*cp++) { 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate case ' ': 2700Sstevel@tonic-gate col++; 2710Sstevel@tonic-gate continue; 2720Sstevel@tonic-gate 2730Sstevel@tonic-gate case '\t': 2740Sstevel@tonic-gate col += value(vi_TABSTOP) - (col % value(vi_TABSTOP)); 2750Sstevel@tonic-gate continue; 2760Sstevel@tonic-gate 2770Sstevel@tonic-gate default: 2780Sstevel@tonic-gate cp--; 2790Sstevel@tonic-gate CP(ocp, cp); 2800Sstevel@tonic-gate return (col); 2810Sstevel@tonic-gate } 2820Sstevel@tonic-gate } 2830Sstevel@tonic-gate 2840Sstevel@tonic-gate unsigned char *cntrlhm = (unsigned char *)"^H discarded\n"; 2850Sstevel@tonic-gate 286*802Scf46844 void 287*802Scf46844 checkjunk(unsigned char c) 2880Sstevel@tonic-gate { 2890Sstevel@tonic-gate 2900Sstevel@tonic-gate if (junkbs == 0 && c == '\b') { 2910Sstevel@tonic-gate write(2, cntrlhm, 13); 2920Sstevel@tonic-gate junkbs = 1; 2930Sstevel@tonic-gate } 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate 296*802Scf46844 void 297*802Scf46844 setin(line *addr) 2980Sstevel@tonic-gate { 2990Sstevel@tonic-gate 3000Sstevel@tonic-gate if (addr == zero) 3010Sstevel@tonic-gate lastin = 0; 3020Sstevel@tonic-gate else 3030Sstevel@tonic-gate getline(*addr), lastin = smunch(0, linebuf); 3040Sstevel@tonic-gate } 305