xref: /illumos-gate/usr/src/cmd/vi/port/ex_get.c (revision 6a634c9d)
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