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