1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 30 /* Copyright (c) 1981 Regents of the University of California */ 31 32 #include "ex.h" 33 #include "ex_tty.h" 34 35 /* 36 * Input routines for command mode. 37 * Since we translate the end of reads into the implied ^D's 38 * we have different flavors of routines which do/don't return such. 39 */ 40 static bool junkbs; 41 short lastc = '\n'; 42 43 void 44 ignchar(void) 45 { 46 (void)getchar(); 47 } 48 49 int 50 getchar(void) 51 { 52 int c; 53 54 do 55 c = getcd(); 56 while (!globp && c == CTRL('d')); 57 return (c); 58 } 59 60 int 61 getcd(void) 62 { 63 int c; 64 extern short slevel; 65 66 again: 67 c = getach(); 68 if (c == EOF) 69 return (c); 70 if (!inopen && slevel==0) 71 if (!globp && c == CTRL('d')) 72 setlastchar('\n'); 73 else if (junk(c)) { 74 checkjunk(c); 75 goto again; 76 } 77 return (c); 78 } 79 80 int 81 peekchar(void) 82 { 83 84 if (peekc == 0) 85 peekc = getchar(); 86 return (peekc); 87 } 88 89 int 90 peekcd(void) 91 { 92 if (peekc == 0) 93 peekc = getcd(); 94 return (peekc); 95 } 96 97 int verbose; 98 int 99 getach(void) 100 { 101 int c, i, prev; 102 static unsigned char inputline[128]; 103 104 c = peekc; 105 if (c != 0) { 106 peekc = 0; 107 return (c); 108 } 109 if (globp) { 110 if (*globp) 111 return (*globp++); 112 globp = 0; 113 return (lastc = EOF); 114 } 115 top: 116 if (input) { 117 if(c = *input++) 118 return (lastc = c); 119 input = 0; 120 } 121 flush(); 122 if (intty) { 123 c = read(0, inputline, sizeof inputline - 4); 124 if (c < 0) 125 return (lastc = EOF); 126 if (c == 0 || inputline[c-1] != '\n') 127 inputline[c++] = CTRL('d'); 128 if (inputline[c-1] == '\n') 129 noteinp(); 130 prev = 0; 131 /* remove nulls from input buffer */ 132 for (i = 0; i < c; i++) 133 if(inputline[i] != 0) 134 inputline[prev++] = inputline[i]; 135 inputline[prev] = 0; 136 input = inputline; 137 goto top; 138 } 139 if (read(0, inputline, 1) != 1) 140 lastc = EOF; 141 else { 142 lastc = inputline[0]; 143 if (verbose) 144 write(2, inputline, 1); 145 } 146 return (lastc); 147 } 148 149 /* 150 * Input routine for insert/append/change in command mode. 151 * Most work here is in handling autoindent. 152 */ 153 static short lastin; 154 155 int 156 gettty(void) 157 { 158 int c = 0; 159 unsigned char *cp = genbuf; 160 unsigned char hadup = 0; 161 extern int (*Pline)(); 162 int offset = Pline == numbline ? 8 : 0; 163 int ch; 164 165 if (intty && !inglobal) { 166 if (offset) { 167 holdcm = 1; 168 viprintf(" %4d ", lineDOT() + 1); 169 flush(); 170 holdcm = 0; 171 } 172 if (value(vi_AUTOINDENT) ^ aiflag) { 173 holdcm = 1; 174 if (value(vi_LISP)) 175 lastin = lindent(dot + 1); 176 gotab(lastin + offset); 177 while ((c = getcd()) == CTRL('d')) { 178 if (lastin == 0 && isatty(0) == -1) { 179 holdcm = 0; 180 return (EOF); 181 } 182 lastin = backtab(lastin); 183 gotab(lastin + offset); 184 } 185 switch (c) { 186 187 case '^': 188 case '0': 189 ch = getcd(); 190 if (ch == CTRL('d')) { 191 if (c == '0') 192 lastin = 0; 193 if (!over_strike) { 194 putchar((int)('\b' | QUOTE)); 195 putchar((int)(' ' | QUOTE)); 196 putchar((int)('\b' | QUOTE)); 197 } 198 gotab(offset); 199 hadup = 1; 200 c = getchar(); 201 } else 202 ungetchar(ch); 203 break; 204 205 case '.': 206 if (peekchar() == '\n') { 207 ignchar(); 208 noteinp(); 209 holdcm = 0; 210 return (EOF); 211 } 212 break; 213 214 case '\n': 215 hadup = 1; 216 break; 217 } 218 } 219 flush(); 220 holdcm = 0; 221 } 222 if (c == 0) 223 c = getchar(); 224 while (c != EOF && c != '\n') { 225 if (cp > &genbuf[LBSIZE - 2]) 226 error(gettext("Input line too long")); 227 *cp++ = c; 228 c = getchar(); 229 } 230 if (c == EOF) { 231 if (inglobal) 232 ungetchar(EOF); 233 return (EOF); 234 } 235 *cp = 0; 236 cp = linebuf; 237 if ((value(vi_AUTOINDENT) ^ aiflag) && hadup == 0 && intty && !inglobal) { 238 lastin = c = smunch(lastin, genbuf); 239 for (c = lastin; c >= value(vi_TABSTOP); c -= value(vi_TABSTOP)) 240 *cp++ = '\t'; 241 for (; c > 0; c--) 242 *cp++ = ' '; 243 } 244 CP(cp, genbuf); 245 if (linebuf[0] == '.' && linebuf[1] == 0) 246 return (EOF); 247 return (0); 248 } 249 250 /* 251 * Crunch the indent. 252 * Hard thing here is that in command mode some of the indent 253 * is only implicit, so we must seed the column counter. 254 * This should really be done differently so as to use the whitecnt routine 255 * and also to hack indenting for LISP. 256 */ 257 int 258 smunch(int col, unsigned char *ocp) 259 { 260 unsigned char *cp; 261 262 cp = ocp; 263 for (;;) 264 switch (*cp++) { 265 266 case ' ': 267 col++; 268 continue; 269 270 case '\t': 271 col += value(vi_TABSTOP) - (col % value(vi_TABSTOP)); 272 continue; 273 274 default: 275 cp--; 276 CP(ocp, cp); 277 return (col); 278 } 279 } 280 281 unsigned char *cntrlhm = (unsigned char *)"^H discarded\n"; 282 283 void 284 checkjunk(unsigned char c) 285 { 286 287 if (junkbs == 0 && c == '\b') { 288 write(2, cntrlhm, 13); 289 junkbs = 1; 290 } 291 } 292 293 void 294 setin(line *addr) 295 { 296 297 if (addr == zero) 298 lastin = 0; 299 else 300 getaline(*addr), lastin = smunch(0, linebuf); 301 } 302