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