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