1 /*
2 *       Echo line reading and writing.
3 * Common routines for reading
4 * and writing characters in the echo line area
5 * of the display screen. Used by the entire
6 * known universe.
7 */
8 #include    "def.h"
9 
10 void eerase ();
11 char ereply ();
12 char eread ();
13 void eformat ();
14 void eputi ();
15 void eputs ();
16 void eputc ();
17 
18 
19 extern char MSG_null[];
20 extern char MSG_y_n[];
21 extern char MSG_hex_dig[];
22 extern char MSG_hit_key[];
23 
24 int epresf = FALSE;		/* Stuff in echo line flag. */
25 
26 /*
27 * Erase the echo line.
28 */
29 void
eerase()30 eerase ()
31 {
32     writ_echo (MSG_null);	/* clear the echo line */
33     epresf = FALSE;
34 }
35 
36 /*
37 * Ask "yes" or "no" question.
38 * Return ABORT if the user answers the question
39 * with the abort ("^G") character. Return FALSE
40 * for "no" and TRUE for "yes". No formatting
41 * services are available.
42 */
43 char
eyesno(sp)44 eyesno (sp)
45     char *sp;
46 {
47 
48     register char s;
49     char buf[NCOL];
50 
51     for (;;)
52     {
53 
54 	s = ereply (MSG_y_n, buf, sizeof (buf), sp);
55 	if (s == ABORT)
56 	    return (ABORT);
57 	if (s != FALSE)
58 	{
59 
60 	    if (buf[0] == 'y' || buf[0] == 'Y')
61 		return (TRUE);
62 	    if (buf[0] == 'n' || buf[0] == 'N')
63 		return (FALSE);
64 	}
65 
66     }
67 
68 }
69 
70 /*
71 * Write out a prompt, and read back a
72 * reply. The prompt is now written out with full "eprintf"
73 * formatting, although the arguments are in a rather strange
74 * place. This is always a new message, there is no auto
75 * completion, and the return is echoed as such.
76 */
77 /* VARARGS3 */
78 char
ereply(fp,buf,nbuf,arg)79 ereply (fp, buf, nbuf, arg)
80     char *fp;
81     char *buf;
82     int nbuf;
83     char *arg;
84 {
85     return (eread (fp, buf, nbuf, EFNEW | EFCR, arg));
86 }
87 
88 /*
89 * This is the general "read input from the
90 * echo line" routine. The basic idea is that the prompt
91 * string "prompt" is written to the echo line, and a one
92 * line reply is read back into the supplied "buf" (with
93 * maximum length "len"). The "flag" contains EFNEW (a
94 * new prompt), an EFAUTO (autocomplete), or EFCR (echo
95 * the carriage return as CR).
96 */
97 char
eread(fp,buf,nbuf,flag,ap)98 eread (fp, buf, nbuf, flag, ap)
99     char *fp;
100     char *buf;
101     char *ap;
102     int nbuf, flag;
103 {
104 
105     register int cpos;
106     register SYMBOL *sp1;
107     register SYMBOL *sp2;
108     register int i;
109     register int c;
110     register int h;
111     register int nhits;
112     register int nxtra;
113     register int bxtra;
114 
115     int quote_flag;
116 
117     quote_flag = 0;
118     cpos = 0;
119     if (kbdmop != NULL)
120     {
121 	/* In a macro.      */
122 	while ((c = *kbdmop++) != '\0')
123 	    buf[cpos++] = c;
124 	buf[cpos] = '\0';
125 	goto done;
126     }
127 
128     if ((flag & EFNEW) != 0 || ttrow != nrow - 1)
129     {
130 
131 	ttcolor (CTEXT);
132 	ttmove (nrow - 1, 0);
133 	epresf = TRUE;
134     }
135     else
136 	eputc (' ');
137     eformat (fp, ap);
138     tteeol ();
139     ttflush ();
140     for (;;)
141     {
142 	c = getkey ();
143 	if (c == ' ' && (flag & EFAUTO) != 0)
144 	{
145 	    nhits = 0;
146 	    nxtra = HUGE;
147 	    for (h = 0; h < NSHASH; ++h)
148 	    {
149 		sp1 = symbol[h];
150 		while (sp1 != NULL)
151 		{
152 		    for (i = 0; i < cpos; ++i)
153 		    {
154 			if (buf[i] != sp1->s_name[i])
155 			    break;
156 		    }
157 
158 		    if (i == cpos)
159 		    {
160 			if (nhits == 0)
161 			    sp2 = sp1;
162 			++nhits;
163 			bxtra = getxtra (sp1, sp2, cpos);
164 			if (bxtra < nxtra)
165 			    nxtra = bxtra;
166 		    }
167 
168 		    sp1 = sp1->s_symp;
169 		}
170 	    }
171 
172 	    if (nhits == 0)	/* No completion.   */
173 		continue;
174 	    for (i = 0; i < nxtra && cpos < nbuf - 1; ++i)
175 	    {
176 		c = sp2->s_name[cpos];
177 		buf[cpos++] = c;
178 		eputc (c);
179 	    }
180 
181 	    ttflush ();
182 	    if (nhits != 1)	/* Fake a CR if there   */
183 		continue;	/* is 1 choice.     */
184 	    c = (KCTRL | 'M');
185 	}
186 	if (quote_flag)
187 	{
188 	    c = c & 0x1f;
189 	    quote_flag = 0;
190 	}
191 
192 
193 	switch (c)
194 	{
195 	case (KCTRL | 'Q'):
196 	    quote_flag = 1;
197 	    break;
198 	case (KCTRL | 'M'):	/* Return, done.    */
199 	case (KCTRL | 'J'):	/* Linefeed, done.  */
200 	    buf[cpos] = '\0';
201 	    if (kbdmip != NULL)
202 	    {
203 		if (kbdmip + cpos + 1 > &kbdm[NKBDM - 3])
204 		{
205 		    (void) ctrlg (FALSE, 0, KRANDOM);
206 		    ttflush ();
207 		    return (ABORT);
208 		}
209 
210 		for (i = 0; i < cpos; ++i)
211 		    *kbdmip++ = buf[i];
212 		*kbdmip++ = '\0';
213 	    }
214 
215 	    if ((flag & EFCR) != 0)
216 	    {
217 		ttputc (0x0D);
218 		ttflush ();
219 	    }
220 
221 	    goto done;
222 
223 	case (KCTRL | 'G'):	/* Bell, abort.     */
224 	    eputc (0x07);
225 	    (void) ctrlg (FALSE, 0, KRANDOM);
226 	    ttflush ();
227 	    return (ABORT);
228 
229 	case 0x7F:		/* Rubout, erase.   */
230 	case (KCTRL | 'H'):	/* Backspace, erase.    */
231 	    if (cpos != 0)
232 	    {
233 		ttputc ('\b');
234 		ttputc (' ');
235 		ttputc ('\b');
236 		--ttcol;
237 		if (ISCTRL (buf[--cpos]) != FALSE)
238 		{
239 		    ttputc ('\b');
240 		    ttputc (' ');
241 		    ttputc ('\b');
242 		    --ttcol;
243 		}
244 
245 		ttflush ();
246 	    }
247 	    break;
248 
249 	case (KCTRL | 'U'):	/* C-U, kill line.  */
250 	    while (cpos != 0)
251 	    {
252 		ttputc ('\b');
253 		ttputc (' ');
254 		ttputc ('\b');
255 		--ttcol;
256 		if (ISCTRL (buf[--cpos]) != FALSE)
257 		{
258 		    ttputc ('\b');
259 		    ttputc (' ');
260 		    ttputc ('\b');
261 		    --ttcol;
262 		}
263 
264 	    }
265 
266 	    ttflush ();
267 	    break;
268 
269 	default:		/* All the rest.    */
270 	    if ((cpos < nbuf - 1) && ((c & ~KCHAR) == 0))
271 	    {
272 		buf[cpos++] = c;
273 		eputc (c);
274 		ttflush ();
275 	    }
276 	}			/* End switch */
277 
278     }
279 
280   done:
281     if (buf[0] == '\0')
282 	return (FALSE);
283     return (TRUE);
284 }
285 
286 /*
287 * The "sp1" and "sp2" point to extended command
288 * symbol table entries. The "cpos" is a horizontal position
289 * in the name. Return the longest block of characters that can
290 * be autocompleted at this point. Sometimes the two symbols
291 * are the same, but this is normal.
292 */
293 int
getxtra(sp1,sp2,cpos)294 getxtra (sp1, sp2, cpos)
295     SYMBOL *sp1;
296     SYMBOL *sp2;
297     int cpos;
298 {
299 
300     register int i;
301 
302     i = cpos;
303     for (;;)
304     {
305 
306 	if (sp1->s_name[i] != sp2->s_name[i])
307 	    break;
308 	if (sp1->s_name[i] == '\0')
309 	    break;
310 	++i;
311     }
312 
313     return (i - cpos);
314 }
315 
316 /*
317 * Printf style formatting. This is
318 * called by both "eprintf" and "ereply", to provide
319 * formatting services to their clients. The move to the
320 * start of the echo line, and the erase to the end of
321 * the echo line, is done by the caller.
322 */
323 void
eformat(fp,ap)324 eformat (fp, ap)
325     char *fp;
326     char *ap;
327 {
328 
329     register int c;
330 
331     while ((c = *fp++) != '\0')
332     {
333 
334 	if (c != '%')
335 	    eputc (c);
336 	else
337 	{
338 
339 	    c = *fp++;
340 	    switch (c)
341 	    {
342 
343 	    case 'd':
344 		eputi (*(int *) ap, 10);
345 		ap += sizeof (int);
346 		break;
347 
348 	    case 'x':		/* krw */
349 		eputi (*(int *) ap, 16);
350 		ap += sizeof (int);
351 		break;
352 
353 	    case 'o':
354 		eputi (*(int *) ap, 8);
355 		ap += sizeof (int);
356 		break;
357 
358 	    case 's':
359 		eputs (ap);
360 		ap += sizeof (char *);
361 		break;
362 
363 	    default:
364 		eputc (c);
365 	    }
366 
367 	}
368 
369     }
370 
371 }
372 
373 /*
374 * Put integer, in radix "r".
375 */
376 void
eputi(i,r)377 eputi (i, r)
378     int i;
379     int r;
380 {
381     static char *convert =
382     {
383 	MSG_hex_dig
384     };
385 
386 
387     register int q;
388 
389     if ((q = i / r) != 0)
390 	eputi (q, r);
391     eputc (convert[i % r]);
392 
393 }
394 
395 /*
396 * Put string.
397 */
398 void
eputs(s)399 eputs (s)
400     char *s;
401 {
402     register int c;
403 
404     while ((c = *s++) != '\0')
405 	eputc (c);
406 }
407 
408 /*
409 * Put character. Watch for
410 * control characters, and for the line
411 * getting too long.
412 */
413 void
eputc(c)414 eputc (c)
415     int c;
416 {
417 
418     if (ttcol < ncol)
419     {
420 
421 	if (ISCTRL (c) != FALSE)
422 	{
423 
424 	    eputc ('^');
425 	    c ^= 0x40;
426 	}
427 
428 	ttputc (c);
429 	++ttcol;
430     }
431 
432 }
433 
434 /*
435  *   Print warning message and wait for the user to hit a key.
436  */
437 void
err_echo(buf)438 err_echo (buf)
439     char *buf;
440 {
441     char ch[NCOL * 2];
442 
443     strcpy (ch, buf);
444     strcat (ch, MSG_hit_key);
445     writ_echo (ch);
446     ttbeep ();
447     while (ttgetc () != CTL_G);
448     {
449 	ttbeep ();
450 	ttflush ();
451     }
452 }
453