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