xref: /original-bsd/usr.bin/ex/ex_get.c (revision ec7df300)
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.6 (Berkeley) 06/07/85";
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(getchar());
25 }
26 
27 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 = 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 	struct stat statb;
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, inline, sizeof inline - 4);
100 		if (c < 0)
101 			return (lastc = EOF);
102 		if (c == 0 || inline[c-1] != '\n')
103 			inline[c++] = CTRL(d);
104 		if (inline[c-1] == '\n')
105 			noteinp();
106 		inline[c] = 0;
107 		for (c--; c >= 0; c--)
108 			if (inline[c] == 0)
109 				inline[c] = QUOTE;
110 		input = inline;
111 		goto top;
112 	}
113 	c = read(0, inline, sizeof inline - 1);
114 	if(c <= 0)
115 		return(lastc = EOF);
116 	inline[c] = '\0';
117 	input = inline;
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 			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 						putchar('\b' | QUOTE);
169 						putchar(' ' | QUOTE);
170 						putchar('\b' | QUOTE);
171 					}
172 					tab(offset);
173 					hadup = 1;
174 					c = 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 = getchar();
198 	while (c != EOF && c != '\n') {
199 		if (cp > &genbuf[LBSIZE - 2])
200 			error("Input line too long");
201 		*cp++ = c;
202 		c = 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