xref: /openbsd-src/usr.bin/mg/echo.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: echo.c,v 1.46 2006/04/02 17:18:58 kjell Exp $	*/
2 
3 /* This file is in the public domain. */
4 
5 /*
6  *	Echo line reading and writing.
7  *
8  * Common routines for reading and writing characters in the echo line area
9  * of the display screen. Used by the entire known universe.
10  */
11 
12 #include "def.h"
13 #include "key.h"
14 #ifndef NO_MACRO
15 #include "macro.h"
16 #endif /* !NO_MACRO */
17 
18 #include "funmap.h"
19 
20 #include <stdarg.h>
21 #include <term.h>
22 
23 static char	*veread(const char *, char *, size_t, int, va_list);
24 static int	 complt(int, int, char *, size_t, int, int *);
25 static int	 complt_list(int, char *, int);
26 static void	 eformat(const char *, va_list);
27 static void	 eputi(int, int);
28 static void	 eputl(long, int);
29 static void	 eputs(const char *);
30 static void	 eputc(char);
31 static struct list	*copy_list(struct list *);
32 
33 int		epresf = FALSE;		/* stuff in echo line flag */
34 
35 /*
36  * Erase the echo line.
37  */
38 void
39 eerase(void)
40 {
41 	ttcolor(CTEXT);
42 	ttmove(nrow - 1, 0);
43 	tteeol();
44 	ttflush();
45 	epresf = FALSE;
46 }
47 
48 /*
49  * Ask a "yes" or "no" question.  Return ABORT if the user answers the
50  * question with the abort ("^G") character.  Return FALSE for "no" and
51  * TRUE for "yes".  No formatting services are available.  No newline
52  * required.
53  */
54 int
55 eyorn(const char *sp)
56 {
57 	int	 s;
58 
59 #ifndef NO_MACRO
60 	if (inmacro)
61 		return (TRUE);
62 #endif /* !NO_MACRO */
63 	ewprintf("%s? (y or n) ", sp);
64 	for (;;) {
65 		s = getkey(FALSE);
66 		if (s == 'y' || s == 'Y' || s == ' ')
67 			return (TRUE);
68 		if (s == 'n' || s == 'N' || s == CCHR('M'))
69 			return (FALSE);
70 		if (s == CCHR('G'))
71 			return (ctrlg(FFRAND, 1));
72 		ewprintf("Please answer y or n.  %s? (y or n) ", sp);
73 	}
74 	/* NOTREACHED */
75 }
76 
77 /*
78  * Like eyorn, but for more important questions.  User must type all of
79  * "yes" or "no" and the trailing newline.
80  */
81 int
82 eyesno(const char *sp)
83 {
84 	char	 buf[64], *rep;
85 
86 #ifndef NO_MACRO
87 	if (inmacro)
88 		return (TRUE);
89 #endif /* !NO_MACRO */
90 	rep = eread("%s? (yes or no) ", buf, sizeof(buf),
91 	    EFNUL | EFNEW | EFCR, sp);
92 	for (;;) {
93 		if (rep == NULL)
94 			return (ABORT);
95 		if (rep[0] != '\0') {
96 #ifndef NO_MACRO
97 			if (macrodef) {
98 				struct line	*lp = maclcur;
99 
100 				maclcur = lp->l_bp;
101 				maclcur->l_fp = lp->l_fp;
102 				free(lp);
103 			}
104 #endif /* !NO_MACRO */
105 			if ((rep[0] == 'y' || rep[0] == 'Y') &&
106 			    (rep[1] == 'e' || rep[1] == 'E') &&
107 			    (rep[2] == 's' || rep[2] == 'S') &&
108 			    (rep[3] == '\0'))
109 				return (TRUE);
110 			if ((rep[0] == 'n' || rep[0] == 'N') &&
111 			    (rep[1] == 'o' || rep[0] == 'O') &&
112 			    (rep[2] == '\0'))
113 				return (FALSE);
114 		}
115 		rep = eread("Please answer yes or no.  %s? (yes or no) ",
116 		    buf, sizeof(buf), EFNUL | EFNEW | EFCR, sp);
117 	}
118 	/* NOTREACHED */
119 }
120 
121 /*
122  * This is the general "read input from the echo line" routine.  The basic
123  * idea is that the prompt string "prompt" is written to the echo line, and
124  * a one line reply is read back into the supplied "buf" (with maximum
125  * length "len").
126  * XXX: When checking for an empty return value, always check rep, *not* buf
127  * as buf may be freed in pathological cases.
128  */
129 /* VARARGS */
130 char *
131 eread(const char *fmt, char *buf, size_t nbuf, int flag, ...)
132 {
133 	va_list	 ap;
134 	char	*rep;
135 
136 	va_start(ap, flag);
137 	rep = veread(fmt, buf, nbuf, flag, ap);
138 	va_end(ap);
139 	return (rep);
140 }
141 
142 static char *
143 veread(const char *fp, char *buf, size_t nbuf, int flag, va_list ap)
144 {
145 	int	 dynbuf = (buf == NULL);
146 	int	 cpos, epos;		/* cursor, end position in buf */
147 	int	 c, i, y;
148 	int	 cplflag = FALSE;	/* display completion list */
149 	int	 cwin = FALSE;		/* completion list created */
150 	int	 mr = 0;		/* match left arrow */
151 	int	 ml = 0;		/* match right arrow */
152 	int	 esc = 0;		/* position in esc pattern */
153 	struct buffer	*bp;			/* completion list buffer */
154 	struct mgwin	*wp;			/* window for compl list */
155 	int	 match;			/* esc match found */
156 	int	 cc, rr;		/* saved ttcol, ttrow */
157 	char	*ret;			/* return value */
158 
159 #ifndef NO_MACRO
160 	if (inmacro) {
161 		if (dynbuf) {
162 			if ((buf = malloc(maclcur->l_used + 1)) == NULL)
163 				return (NULL);
164 		} else if (maclcur->l_used >= nbuf)
165 			return (NULL);
166 		bcopy(maclcur->l_text, buf, maclcur->l_used);
167 		buf[maclcur->l_used] = '\0';
168 		maclcur = maclcur->l_fp;
169 		return (buf);
170 	}
171 #endif /* !NO_MACRO */
172 	epos = cpos = 0;
173 	ml = mr = esc = 0;
174 	cplflag = FALSE;
175 
176 	if ((flag & EFNEW) != 0 || ttrow != nrow - 1) {
177 		ttcolor(CTEXT);
178 		ttmove(nrow - 1, 0);
179 		epresf = TRUE;
180 	} else
181 		eputc(' ');
182 	eformat(fp, ap);
183 	if ((flag & EFDEF) != 0) {
184 		if (buf == NULL)
185 			return (NULL);
186 		eputs(buf);
187 		epos = cpos += strlen(buf);
188 	}
189 	tteeol();
190 	ttflush();
191 	for (;;) {
192 		c = getkey(FALSE);
193 		if ((flag & EFAUTO) != 0 && (c == ' ' || c == CCHR('I'))) {
194 			if (cplflag == TRUE) {
195 				complt_list(flag, buf, cpos);
196 				cwin = TRUE;
197 			} else if (complt(flag, c, buf, nbuf, epos, &i) == TRUE) {
198 				cplflag = TRUE;
199 				epos += i;
200 				cpos = epos;
201 			}
202 			continue;
203 		}
204 		cplflag = FALSE;
205 
206 		if (esc > 0) { /* ESC sequence started */
207 			match = 0;
208 			if (ml == esc && key_left[ml] && c == key_left[ml]) {
209 				match++;
210 				if (key_left[++ml] == '\0') {
211 					c = CCHR('B');
212 					esc = 0;
213 				}
214 			}
215 			if (mr == esc && key_right[mr] && c == key_right[mr]) {
216 				match++;
217 				if (key_right[++mr] == '\0') {
218 					c = CCHR('F');
219 					esc = 0;
220 				}
221 			}
222 			if (match == 0) {
223 				esc = 0;
224 				continue;
225 				/* hack. how do we know esc pattern is done? */
226 			}
227 			if (esc > 0) {
228 				esc++;
229 				continue;
230 			}
231 		}
232 		switch (c) {
233 		case CCHR('A'): /* start of line */
234 			while (cpos > 0) {
235 				if (ISCTRL(buf[--cpos]) != FALSE) {
236 					ttputc('\b');
237 					--ttcol;
238 				}
239 				ttputc('\b');
240 				--ttcol;
241 			}
242 			ttflush();
243 			break;
244 		case CCHR('D'):
245 			if (cpos != epos) {
246 				tteeol();
247 				y = buf[cpos];
248 				epos--;
249 				rr = ttrow;
250 				cc = ttcol;
251 				for (i = cpos; i < epos; i++) {
252 					buf[i] = buf[i + 1];
253 					eputc(buf[i]);
254 				}
255 				ttmove(rr, cc);
256 				ttflush();
257 			}
258 			break;
259 		case CCHR('E'): /* end of line */
260 			while (cpos < epos) {
261 				eputc(buf[cpos++]);
262 			}
263 			ttflush();
264 			break;
265 		case CCHR('B'): /* back */
266 			if (cpos > 0) {
267 				if (ISCTRL(buf[--cpos]) != FALSE) {
268 					ttputc('\b');
269 					--ttcol;
270 				}
271 				ttputc('\b');
272 				--ttcol;
273 				ttflush();
274 			}
275 			break;
276 		case CCHR('F'): /* forw */
277 			if (cpos < epos) {
278 				eputc(buf[cpos++]);
279 				ttflush();
280 			}
281 			break;
282 		case CCHR('Y'): /* yank from kill buffer */
283 			i = 0;
284 			while ((y = kremove(i++)) >= 0 && y != '\n') {
285 				int t;
286 				if (dynbuf && epos + 1 >= nbuf) {
287 					void *newp;
288 					size_t newsize = epos + epos + 16;
289 					if ((newp = realloc(buf, newsize))
290 					    == NULL)
291 						goto fail;
292 					buf = newp;
293 					nbuf = newsize;
294 				}
295 				for (t = epos; t > cpos; t--)
296 					buf[t] = buf[t - 1];
297 				buf[cpos++] = (char)y;
298 				epos++;
299 				eputc((char)y);
300 				cc = ttcol;
301 				rr = ttrow;
302 				for (t = cpos; t < epos; t++)
303 					eputc(buf[t]);
304 				ttmove(rr, cc);
305 			}
306 			ttflush();
307 			break;
308 		case CCHR('K'): /* copy here-EOL to kill buffer */
309 			kdelete();
310 			for (i = cpos; i < epos; i++)
311 				kinsert(buf[i], KFORW);
312 			tteeol();
313 			epos = cpos;
314 			ttflush();
315 			break;
316 		case CCHR('['):
317 			ml = mr = esc = 1;
318 			break;
319 		case CCHR('J'):
320 			c = CCHR('M');
321 			/* FALLTHROUGH */
322 		case CCHR('M'):			/* return, done */
323 			/* if there's nothing in the minibuffer, abort */
324 			if (epos == 0 && !(flag & EFNUL)) {
325 				(void)ctrlg(FFRAND, 0);
326 				ttflush();
327 				return (NULL);
328 			}
329 			if ((flag & EFFUNC) != 0) {
330 				if (complt(flag, c, buf, nbuf, epos, &i)
331 				    == FALSE)
332 					continue;
333 				if (i > 0)
334 					epos += i;
335 			}
336 			buf[epos] = '\0';
337 			if ((flag & EFCR) != 0) {
338 				ttputc(CCHR('M'));
339 				ttflush();
340 			}
341 #ifndef NO_MACRO
342 			if (macrodef) {
343 				struct line	*lp;
344 
345 				if ((lp = lalloc(cpos)) == NULL) {
346 					static char falseval[] = "";
347 					/* XXX hackish */
348 					if (dynbuf && buf != NULL)
349 						free(buf);
350 					return (falseval);
351 				}
352 				lp->l_fp = maclcur->l_fp;
353 				maclcur->l_fp = lp;
354 				lp->l_bp = maclcur;
355 				maclcur = lp;
356 				bcopy(buf, lp->l_text, cpos);
357 			}
358 #endif /* !NO_MACRO */
359 			ret = buf;
360 			goto done;
361 		case CCHR('G'):			/* bell, abort */
362 			eputc(CCHR('G'));
363 			(void)ctrlg(FFRAND, 0);
364 			ttflush();
365 			ret = NULL;
366 			goto done;
367 		case CCHR('H'):			/* rubout, erase */
368 		case CCHR('?'):
369 			if (cpos != 0) {
370 				y = buf[--cpos];
371 				epos--;
372 				ttputc('\b');
373 				ttcol--;
374 				if (ISCTRL(y) != FALSE) {
375 					ttputc('\b');
376 					ttcol--;
377 				}
378 				rr = ttrow;
379 				cc = ttcol;
380 				for (i = cpos; i < epos; i++) {
381 					buf[i] = buf[i + 1];
382 					eputc(buf[i]);
383 				}
384 				ttputc(' ');
385 				if (ISCTRL(y) != FALSE) {
386 					ttputc(' ');
387 					ttputc('\b');
388 				}
389 				ttputc('\b');
390 				ttmove(rr, cc);
391 				ttflush();
392 			}
393 			break;
394 		case CCHR('X'):			/* kill line */
395 		case CCHR('U'):
396 			while (cpos != 0) {
397 				ttputc('\b');
398 				ttputc(' ');
399 				ttputc('\b');
400 				--ttcol;
401 				if (ISCTRL(buf[--cpos]) != FALSE) {
402 					ttputc('\b');
403 					ttputc(' ');
404 					ttputc('\b');
405 					--ttcol;
406 				}
407 				epos--;
408 			}
409 			ttflush();
410 			break;
411 		case CCHR('W'):			/* kill to beginning of word */
412 			while ((cpos > 0) && !ISWORD(buf[cpos - 1])) {
413 				ttputc('\b');
414 				ttputc(' ');
415 				ttputc('\b');
416 				--ttcol;
417 				if (ISCTRL(buf[--cpos]) != FALSE) {
418 					ttputc('\b');
419 					ttputc(' ');
420 					ttputc('\b');
421 					--ttcol;
422 				}
423 				epos--;
424 			}
425 			while ((cpos > 0) && ISWORD(buf[cpos - 1])) {
426 				ttputc('\b');
427 				ttputc(' ');
428 				ttputc('\b');
429 				--ttcol;
430 				if (ISCTRL(buf[--cpos]) != FALSE) {
431 					ttputc('\b');
432 					ttputc(' ');
433 					ttputc('\b');
434 					--ttcol;
435 				}
436 				epos--;
437 			}
438 			ttflush();
439 			break;
440 		case CCHR('\\'):
441 		case CCHR('Q'):			/* quote next */
442 			c = getkey(FALSE);
443 			/* FALLTHROUGH */
444 		default:
445 			if (dynbuf && epos + 1 >= nbuf) {
446 				void *newp;
447 				size_t newsize = epos + epos + 16;
448 				if ((newp = realloc(buf, newsize)) == NULL)
449 					goto fail;
450 				buf = newp;
451 				nbuf = newsize;
452 			}
453 			for (i = epos; i > cpos; i--)
454 				buf[i] = buf[i - 1];
455 			buf[cpos++] = (char)c;
456 			epos++;
457 			eputc((char)c);
458 			cc = ttcol;
459 			rr = ttrow;
460 			for (i = cpos; i < epos; i++)
461 				eputc(buf[i]);
462 			ttmove(rr, cc);
463 			ttflush();
464 		}
465 	}
466 done:
467 	if (cwin == TRUE) {
468 		/* blow away cpltion window */
469 		bp = bfind("*Completions*", TRUE);
470 		if ((wp = popbuf(bp)) != NULL) {
471 			curwp = wp;
472 			delwind(FFRAND, 1);
473 		}
474 	}
475 	return (ret);
476 fail:
477 	ewprintf("Out of memory");
478 	free(buf);
479 	return (NULL);
480 }
481 
482 /*
483  * Do completion on a list of objects.
484  * c is SPACE, TAB, or CR
485  * return TRUE if matched (or partially matched)
486  * FALSE is result is ambiguous,
487  * ABORT on error.
488  */
489 static int
490 complt(int flags, int c, char *buf, size_t nbuf, int cpos, int *nx)
491 {
492 	struct list	*lh, *lh2;
493 	struct list	*wholelist = NULL;
494 	int	 i, nxtra, nhits, bxtra, msglen, nshown;
495 	int	 wflag = FALSE;
496 	char	*msg;
497 
498 	lh = lh2 = NULL;
499 
500 	if ((flags & EFFUNC) != 0) {
501 		buf[cpos] = '\0';
502 		wholelist = lh = complete_function_list(buf);
503 	} else if ((flags & EFBUF) != 0) {
504 		lh = &(bheadp->b_list);
505 	} else if ((flags & EFFILE) != 0) {
506 		buf[cpos] = '\0';
507 		wholelist = lh = make_file_list(buf);
508 	} else
509 		panic("broken complt call: flags");
510 
511 	if (c == ' ')
512 		wflag = TRUE;
513 	else if (c != '\t' && c != CCHR('M'))
514 		panic("broken complt call: c");
515 
516 	nhits = 0;
517 	nxtra = HUGE;
518 
519 	for (; lh != NULL; lh = lh->l_next) {
520 		if (memcmp(buf, lh->l_name, cpos) != 0)
521 			continue;
522 		if (nhits == 0)
523 			lh2 = lh;
524 		++nhits;
525 		if (lh->l_name[cpos] == '\0')
526 			nxtra = -1; /* exact match */
527 		else {
528 			bxtra = getxtra(lh, lh2, cpos, wflag);
529 			if (bxtra < nxtra)
530 				nxtra = bxtra;
531 			lh2 = lh;
532 		}
533 	}
534 	if (nhits == 0)
535 		msg = " [No match]";
536 	else if (nhits > 1 && nxtra == 0)
537 		msg = " [Ambiguous. Ctrl-G to cancel]";
538 	else {
539 		/*
540 		 * Being lazy - ought to check length, but all things
541 		 * autocompleted have known types/lengths.
542 		 */
543 		if (nxtra < 0 && nhits > 1 && c == ' ')
544 			nxtra = 1; /* ??? */
545 		for (i = 0; i < nxtra && cpos < nbuf; ++i) {
546 			buf[cpos] = lh2->l_name[cpos];
547 			eputc(buf[cpos++]);
548 		}
549 		/* XXX should grow nbuf */
550 		ttflush();
551 		free_file_list(wholelist);
552 		*nx = nxtra;
553 		if (nxtra < 0 && c != CCHR('M')) /* exact */
554 			*nx = 0;
555 		return (TRUE);
556 	}
557 
558 	/*
559 	 * wholelist is NULL if we are doing buffers.  Want to free lists
560 	 * that were created for us, but not the buffer list!
561 	 */
562 	free_file_list(wholelist);
563 
564 	/* Set up backspaces, etc., being mindful of echo line limit. */
565 	msglen = strlen(msg);
566 	nshown = (ttcol + msglen + 2 > ncol) ?
567 		ncol - ttcol - 2 : msglen;
568 	eputs(msg);
569 	ttcol -= (i = nshown);	/* update ttcol!		 */
570 	while (i--)		/* move back before msg		 */
571 		ttputc('\b');
572 	ttflush();		/* display to user		 */
573 	i = nshown;
574 	while (i--)		/* blank out on next flush	 */
575 		eputc(' ');
576 	ttcol -= (i = nshown);	/* update ttcol on BS's		 */
577 	while (i--)
578 		ttputc('\b');	/* update ttcol again!		 */
579 	*nx = nxtra;
580 	return ((nhits > 0) ? TRUE : FALSE);
581 }
582 
583 /*
584  * Do completion on a list of objects, listing instead of completing.
585  */
586 static int
587 complt_list(int flags, char *buf, int cpos)
588 {
589 	struct list	*lh, *lh2, *lh3;
590 	struct list	*wholelist = NULL;
591 	struct buffer	*bp;
592 	int	 i, maxwidth, width;
593 	int	 preflen = 0;
594 	int	 oldrow = ttrow;
595 	int	 oldcol = ttcol;
596 	int	 oldhue = tthue;
597 	char	 *linebuf;
598 	size_t	 linesize, len;
599 	char *cp;
600 
601 	lh = NULL;
602 
603 	ttflush();
604 
605 	/* The results are put into a completion buffer. */
606 	bp = bfind("*Completions*", TRUE);
607 	if (bclear(bp) == FALSE)
608 		return (FALSE);
609 
610 	/*
611 	 * First get the list of objects.  This list may contain only
612 	 * the ones that complete what has been typed, or may be the
613 	 * whole list of all objects of this type.  They are filtered
614 	 * later in any case.  Set wholelist if the list has been
615 	 * cons'ed up just for us, so we can free it later.  We have
616 	 * to copy the buffer list for this function even though we
617 	 * didn't for complt.  The sorting code does destructive
618 	 * changes to the list, which we don't want to happen to the
619 	 * main buffer list!
620 	 */
621 	if ((flags & EFBUF) != 0)
622 		wholelist = lh = copy_list(&(bheadp->b_list));
623 	else if ((flags & EFFUNC) != 0) {
624 		buf[cpos] = '\0';
625 		wholelist = lh = complete_function_list(buf);
626 	} else if ((flags & EFFILE) != 0) {
627 		buf[cpos] = '\0';
628 		wholelist = lh = make_file_list(buf);
629 		/*
630 		 * We don't want to display stuff up to the / for file
631 		 * names preflen is the list of a prefix of what the
632 		 * user typed that should not be displayed.
633 		 */
634 		cp = strrchr(buf, '/');
635 		if (cp)
636 			preflen = cp - buf + 1;
637 	} else
638 		panic("broken complt call: flags");
639 
640 	/*
641 	 * Sort the list, since users expect to see it in alphabetic
642 	 * order.
643 	 */
644 	lh2 = lh;
645 	while (lh2 != NULL) {
646 		lh3 = lh2->l_next;
647 		while (lh3 != NULL) {
648 			if (strcmp(lh2->l_name, lh3->l_name) > 0) {
649 				cp = lh2->l_name;
650 				lh2->l_name = lh3->l_name;
651 				lh3->l_name = cp;
652 			}
653 			lh3 = lh3->l_next;
654 		}
655 		lh2 = lh2->l_next;
656 	}
657 
658 	/*
659 	 * First find max width of object to be displayed, so we can
660 	 * put several on a line.
661 	 */
662 	maxwidth = 0;
663 	lh2 = lh;
664 	while (lh2 != NULL) {
665 		for (i = 0; i < cpos; ++i) {
666 			if (buf[i] != lh2->l_name[i])
667 				break;
668 		}
669 		if (i == cpos) {
670 			width = strlen(lh2->l_name);
671 			if (width > maxwidth)
672 				maxwidth = width;
673 		}
674 		lh2 = lh2->l_next;
675 	}
676 	maxwidth += 1 - preflen;
677 
678 	/*
679 	 * Now do the display.  Objects are written into linebuf until
680 	 * it fills, and then put into the help buffer.
681 	 */
682 	linesize = MAX(ncol, maxwidth) + 1;
683 	if ((linebuf = malloc(linesize)) == NULL)
684 		return (FALSE);
685 	width = 0;
686 
687 	/*
688 	 * We're going to strlcat() into the buffer, so it has to be
689 	 * NUL terminated.
690 	 */
691 	linebuf[0] = '\0';
692 	for (lh2 = lh; lh2 != NULL; lh2 = lh2->l_next) {
693 		for (i = 0; i < cpos; ++i) {
694 			if (buf[i] != lh2->l_name[i])
695 				break;
696 		}
697 		/* if we have a match */
698 		if (i == cpos) {
699 			/* if it wraps */
700 			if ((width + maxwidth) > ncol) {
701 				addline(bp, linebuf);
702 				linebuf[0] = '\0';
703 				width = 0;
704 			}
705 			len = strlcat(linebuf, lh2->l_name + preflen,
706 			    linesize);
707 			width += maxwidth;
708 			if (len < width && width < linesize) {
709 				/* pad so the objects nicely line up */
710 				memset(linebuf + len, ' ',
711 				    maxwidth - strlen(lh2->l_name + preflen));
712 				linebuf[width] = '\0';
713 			}
714 		}
715 	}
716 	if (width > 0)
717 		addline(bp, linebuf);
718 	free(linebuf);
719 
720 	/*
721 	 * Note that we free lists only if they are put in wholelist lists
722 	 * that were built just for us should be freed.  However when we use
723 	 * the buffer list, obviously we don't want it freed.
724 	 */
725 	free_file_list(wholelist);
726 	popbuftop(bp);		/* split the screen and put up the help
727 				 * buffer */
728 	update();		/* needed to make the new stuff actually
729 				 * appear */
730 	ttmove(oldrow, oldcol);	/* update leaves cursor in arbitrary place */
731 	ttcolor(oldhue);	/* with arbitrary color */
732 	ttflush();
733 	return (0);
734 }
735 
736 /*
737  * The "lp1" and "lp2" point to list structures.  The "cpos" is a horizontal
738  * position in the name.  Return the longest block of characters that can be
739  * autocompleted at this point.  Sometimes the two symbols are the same, but
740  * this is normal.
741  */
742 int
743 getxtra(struct list *lp1, struct list *lp2, int cpos, int wflag)
744 {
745 	int	i;
746 
747 	i = cpos;
748 	for (;;) {
749 		if (lp1->l_name[i] != lp2->l_name[i])
750 			break;
751 		if (lp1->l_name[i] == '\0')
752 			break;
753 		++i;
754 		if (wflag && !ISWORD(lp1->l_name[i - 1]))
755 			break;
756 	}
757 	return (i - cpos);
758 }
759 
760 /*
761  * Special "printf" for the echo line.  Each call to "ewprintf" starts a
762  * new line in the echo area, and ends with an erase to end of the echo
763  * line.  The formatting is done by a call to the standard formatting
764  * routine.
765  */
766 /* VARARGS */
767 void
768 ewprintf(const char *fmt, ...)
769 {
770 	va_list	 ap;
771 
772 #ifndef NO_MACRO
773 	if (inmacro)
774 		return;
775 #endif /* !NO_MACRO */
776 	va_start(ap, fmt);
777 	ttcolor(CTEXT);
778 	ttmove(nrow - 1, 0);
779 	eformat(fmt, ap);
780 	va_end(ap);
781 	tteeol();
782 	ttflush();
783 	epresf = TRUE;
784 }
785 
786 /*
787  * Printf style formatting. This is called by both "ewprintf" and "ereply"
788  * to provide formatting services to their clients.  The move to the start
789  * of the echo line, and the erase to the end of the echo line, is done by
790  * the caller.
791  * Note: %c works, and prints the "name" of the character.
792  * %k prints the name of a key (and takes no arguments).
793  */
794 static void
795 eformat(const char *fp, va_list ap)
796 {
797 	char	kname[NKNAME], tmp[100], *cp;
798 	int	c;
799 
800 	while ((c = *fp++) != '\0') {
801 		if (c != '%')
802 			eputc(c);
803 		else {
804 			c = *fp++;
805 			switch (c) {
806 			case 'c':
807 				getkeyname(kname, sizeof(kname), va_arg(ap, int));
808 				eputs(kname);
809 				break;
810 
811 			case 'k':
812 				for (cp = kname, c = 0; c < key.k_count; c++) {
813 					if (c)
814 						*cp++ = ' ';
815 					cp = getkeyname(cp, sizeof(kname) -
816 					    (cp - kname) - 1, key.k_chars[c]);
817 				}
818 				eputs(kname);
819 				break;
820 
821 			case 'd':
822 				eputi(va_arg(ap, int), 10);
823 				break;
824 
825 			case 'o':
826 				eputi(va_arg(ap, int), 8);
827 				break;
828 
829 			case 'p':
830 				snprintf(tmp, sizeof(tmp), "%p",
831 				    va_arg(ap, void *));
832 				eputs(tmp);
833 				break;
834 
835 			case 's':
836 				eputs(va_arg(ap, char *));
837 				break;
838 
839 			case 'l':
840 				/* explicit longword */
841 				c = *fp++;
842 				switch (c) {
843 				case 'd':
844 					eputl(va_arg(ap, long), 10);
845 					break;
846 				default:
847 					eputc(c);
848 					break;
849 				}
850 				break;
851 
852 			default:
853 				eputc(c);
854 			}
855 		}
856 	}
857 }
858 
859 /*
860  * Put integer, in radix "r".
861  */
862 static void
863 eputi(int i, int r)
864 {
865 	int	 q;
866 
867 	if (i < 0) {
868 		eputc('-');
869 		i = -i;
870 	}
871 	if ((q = i / r) != 0)
872 		eputi(q, r);
873 	eputc(i % r + '0');
874 }
875 
876 /*
877  * Put long, in radix "r".
878  */
879 static void
880 eputl(long l, int r)
881 {
882 	long	 q;
883 
884 	if (l < 0) {
885 		eputc('-');
886 		l = -l;
887 	}
888 	if ((q = l / r) != 0)
889 		eputl(q, r);
890 	eputc((int)(l % r) + '0');
891 }
892 
893 /*
894  * Put string.
895  */
896 static void
897 eputs(const char *s)
898 {
899 	int	 c;
900 
901 	while ((c = *s++) != '\0')
902 		eputc(c);
903 }
904 
905 /*
906  * Put character.  Watch for control characters, and for the line getting
907  * too long.
908  */
909 static void
910 eputc(char c)
911 {
912 	if (ttcol + 2 < ncol) {
913 		if (ISCTRL(c)) {
914 			eputc('^');
915 			c = CCHR(c);
916 		}
917 		ttputc(c);
918 		++ttcol;
919 	}
920 }
921 
922 void
923 free_file_list(struct list *lp)
924 {
925 	struct list	*next;
926 
927 	while (lp) {
928 		next = lp->l_next;
929 		free(lp->l_name);
930 		free(lp);
931 		lp = next;
932 	}
933 }
934 
935 static struct list *
936 copy_list(struct list *lp)
937 {
938 	struct list	*current, *last, *nxt;
939 
940 	last = NULL;
941 	while (lp) {
942 		current = malloc(sizeof(struct list));
943 		if (current == NULL) {
944 			/* Free what we have allocated so far */
945 			for (current = last; current; current = nxt) {
946 				nxt = current->l_next;
947 				free(current->l_name);
948 				free(current);
949 			}
950 			return (NULL);
951 		}
952 		current->l_next = last;
953 		current->l_name = strdup(lp->l_name);
954 		last = current;
955 		lp = lp->l_next;
956 	}
957 	return (last);
958 }
959