xref: /original-bsd/usr.bin/ex/ex_get.c (revision 3705696b)
1 /*-
2  * Copyright (c) 1980, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.proprietary.c%
6  */
7 
8 #ifndef lint
9 static char sccsid[] = "@(#)ex_get.c	8.1 (Berkeley) 06/09/93";
10 #endif /* not lint */
11 
12 #include "ex.h"
13 #include "ex_tty.h"
14 
15 /*
16  * Input routines for command mode.
17  * Since we translate the end of reads into the implied ^D's
18  * we have different flavors of routines which do/don't return such.
19  */
20 static	bool junkbs;
21 short	lastc = '\n';
22 
23 ignchar()
24 {
25 	ignore(ex_getchar());
26 }
27 
28 ex_getchar()
29 {
30 	register int c;
31 
32 	do
33 		c = getcd();
34 	while (!globp && c == CTRL('d'));
35 	return (c);
36 }
37 
38 getcd()
39 {
40 	register int c;
41 
42 again:
43 	c = getach();
44 	if (c == EOF)
45 		return (c);
46 	c &= TRIM;
47 	if (!inopen)
48 		if (!globp && c == CTRL('d'))
49 			setlastchar('\n');
50 		else if (junk(c)) {
51 			checkjunk(c);
52 			goto again;
53 		}
54 	return (c);
55 }
56 
57 peekchar()
58 {
59 
60 	if (peekc == 0)
61 		peekc = ex_getchar();
62 	return (peekc);
63 }
64 
65 peekcd()
66 {
67 	if (peekc == 0)
68 		peekc = getcd();
69 	return (peekc);
70 }
71 
72 getach()
73 {
74 	register int c;
75 	static char inputline[BUFSIZ];
76 
77 	c = peekc;
78 	if (c != 0) {
79 		peekc = 0;
80 		return (c);
81 	}
82 	if (globp) {
83 		if (*globp)
84 			return (*globp++);
85 		globp = 0;
86 		return (lastc = EOF);
87 	}
88 top:
89 	if (input) {
90 		if (c = *input++) {
91 			if (c &= TRIM)
92 				return (lastc = c);
93 			goto top;
94 		}
95 		input = 0;
96 	}
97 	flush();
98 	if (intty) {
99 		c = read(0, inputline, sizeof inputline - 4);
100 		if (c < 0)
101 			return (lastc = EOF);
102 		if (c == 0 || inputline[c-1] != '\n')
103 			inputline[c++] = CTRL('d');
104 		if (inputline[c-1] == '\n')
105 			noteinp();
106 		inputline[c] = 0;
107 		for (c--; c >= 0; c--)
108 			if (inputline[c] == 0)
109 				inputline[c] = QUOTE;
110 		input = inputline;
111 		goto top;
112 	}
113 	c = read(0, inputline, sizeof inputline - 1);
114 	if(c <= 0)
115 		return(lastc = EOF);
116 	inputline[c] = '\0';
117 	input = inputline;
118 	goto top;
119 }
120 
121 /*
122  * Input routine for insert/append/change in command mode.
123  * Most work here is in handling autoindent.
124  */
125 static	short	lastin;
126 
127 gettty()
128 {
129 	register int c = 0;
130 	register char *cp = genbuf;
131 	char hadup = 0;
132 	int numbline();
133 	extern int (*Pline)();
134 	int offset = Pline == numbline ? 8 : 0;
135 	int ch;
136 
137 	if (intty && !inglobal) {
138 		if (offset) {
139 			holdcm = 1;
140 			ex_printf("  %4d  ", lineDOT() + 1);
141 			flush();
142 			holdcm = 0;
143 		}
144 		if (value(AUTOINDENT) ^ aiflag) {
145 			holdcm = 1;
146 #ifdef LISPCODE
147 			if (value(LISP))
148 				lastin = lindent(dot + 1);
149 #endif
150 			tab(lastin + offset);
151 			while ((c = getcd()) == CTRL('d')) {
152 				if (lastin == 0 && isatty(0) == -1) {
153 					holdcm = 0;
154 					return (EOF);
155 				}
156 				lastin = backtab(lastin);
157 				tab(lastin + offset);
158 			}
159 			switch (c) {
160 
161 			case '^':
162 			case '0':
163 				ch = getcd();
164 				if (ch == CTRL('d')) {
165 					if (c == '0')
166 						lastin = 0;
167 					if (!OS) {
168 						ex_putchar('\b' | QUOTE);
169 						ex_putchar(' ' | QUOTE);
170 						ex_putchar('\b' | QUOTE);
171 					}
172 					tab(offset);
173 					hadup = 1;
174 					c = ex_getchar();
175 				} else
176 					ungetchar(ch);
177 				break;
178 
179 			case '.':
180 				if (peekchar() == '\n') {
181 					ignchar();
182 					noteinp();
183 					holdcm = 0;
184 					return (EOF);
185 				}
186 				break;
187 
188 			case '\n':
189 				hadup = 1;
190 				break;
191 			}
192 		}
193 		flush();
194 		holdcm = 0;
195 	}
196 	if (c == 0)
197 		c = ex_getchar();
198 	while (c != EOF && c != '\n') {
199 		if (cp > &genbuf[LBSIZE - 2])
200 			error("Input line too long");
201 		*cp++ = c;
202 		c = ex_getchar();
203 	}
204 	if (c == EOF) {
205 		if (inglobal)
206 			ungetchar(EOF);
207 		return (EOF);
208 	}
209 	*cp = 0;
210 	cp = linebuf;
211 	if ((value(AUTOINDENT) ^ aiflag) && hadup == 0 && intty && !inglobal) {
212 		lastin = c = smunch(lastin, genbuf);
213 		for (c = lastin; c >= value(TABSTOP); c -= value(TABSTOP))
214 			*cp++ = '\t';
215 		for (; c > 0; c--)
216 			*cp++ = ' ';
217 	}
218 	CP(cp, genbuf);
219 	if (linebuf[0] == '.' && linebuf[1] == 0)
220 		return (EOF);
221 	return (0);
222 }
223 
224 /*
225  * Crunch the indent.
226  * Hard thing here is that in command mode some of the indent
227  * is only implicit, so we must seed the column counter.
228  * This should really be done differently so as to use the whitecnt routine
229  * and also to hack indenting for LISP.
230  */
231 smunch(col, ocp)
232 	register int col;
233 	char *ocp;
234 {
235 	register char *cp;
236 
237 	cp = ocp;
238 	for (;;)
239 		switch (*cp++) {
240 
241 		case ' ':
242 			col++;
243 			continue;
244 
245 		case '\t':
246 			col += value(TABSTOP) - (col % value(TABSTOP));
247 			continue;
248 
249 		default:
250 			cp--;
251 			CP(ocp, cp);
252 			return (col);
253 		}
254 }
255 
256 char	*cntrlhm =	"^H discarded\n";
257 
258 checkjunk(c)
259 	char c;
260 {
261 
262 	if (junkbs == 0 && c == '\b') {
263 		write(2, cntrlhm, 13);
264 		junkbs = 1;
265 	}
266 }
267 
268 line *
269 setin(addr)
270 	line *addr;
271 {
272 
273 	if (addr == zero)
274 		lastin = 0;
275 	else
276 		getline(*addr), lastin = smunch(0, linebuf);
277 }
278