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
ignchar(void)44 ignchar(void)
45 {
46 (void)getchar();
47 }
48
49 int
getchar(void)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
getcd(void)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
peekchar(void)81 peekchar(void)
82 {
83
84 if (peekc == 0)
85 peekc = getchar();
86 return (peekc);
87 }
88
89 int
peekcd(void)90 peekcd(void)
91 {
92 if (peekc == 0)
93 peekc = getcd();
94 return (peekc);
95 }
96
97 int verbose;
98 int
getach(void)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
gettty(void)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
smunch(int col,unsigned char * ocp)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
checkjunk(unsigned char c)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
setin(line * addr)294 setin(line *addr)
295 {
296
297 if (addr == zero)
298 lastin = 0;
299 else
300 getaline(*addr), lastin = smunch(0, linebuf);
301 }
302