xref: /openbsd-src/usr.bin/mg/echo.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1 /*	$OpenBSD: echo.c,v 1.50 2012/04/12 04:47:59 lum 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 #include "macro.h"
15 
16 #include "funmap.h"
17 
18 #include <stdarg.h>
19 #include <term.h>
20 
21 static char	*veread(const char *, char *, size_t, int, va_list);
22 static int	 complt(int, int, char *, size_t, int, int *);
23 static int	 complt_list(int, char *, int);
24 static void	 eformat(const char *, va_list);
25 static void	 eputi(int, int);
26 static void	 eputl(long, int);
27 static void	 eputs(const char *);
28 static void	 eputc(char);
29 static struct list	*copy_list(struct list *);
30 
31 int		epresf = FALSE;		/* stuff in echo line flag */
32 
33 /*
34  * Erase the echo line.
35  */
36 void
37 eerase(void)
38 {
39 	ttcolor(CTEXT);
40 	ttmove(nrow - 1, 0);
41 	tteeol();
42 	ttflush();
43 	epresf = FALSE;
44 }
45 
46 /*
47  * Ask a "yes" or "no" question.  Return ABORT if the user answers the
48  * question with the abort ("^G") character.  Return FALSE for "no" and
49  * TRUE for "yes".  No formatting services are available.  No newline
50  * required.
51  */
52 int
53 eyorn(const char *sp)
54 {
55 	int	 s;
56 
57 	if (inmacro)
58 		return (TRUE);
59 
60 	ewprintf("%s? (y or n) ", sp);
61 	for (;;) {
62 		s = getkey(FALSE);
63 		if (s == 'y' || s == 'Y' || s == ' ')
64 			return (TRUE);
65 		if (s == 'n' || s == 'N' || s == CCHR('M'))
66 			return (FALSE);
67 		if (s == CCHR('G'))
68 			return (ctrlg(FFRAND, 1));
69 		ewprintf("Please answer y or n.  %s? (y or n) ", sp);
70 	}
71 	/* NOTREACHED */
72 }
73 
74 /*
75  * Like eyorn, but for more important questions.  User must type all of
76  * "yes" or "no" and the trailing newline.
77  */
78 int
79 eyesno(const char *sp)
80 {
81 	char	 buf[64], *rep;
82 
83 	if (inmacro)
84 		return (TRUE);
85 
86 	rep = eread("%s? (yes or no) ", buf, sizeof(buf),
87 	    EFNUL | EFNEW | EFCR, sp);
88 	for (;;) {
89 		if (rep == NULL)
90 			return (ABORT);
91 		if (rep[0] != '\0') {
92 			if (macrodef) {
93 				struct line	*lp = maclcur;
94 
95 				maclcur = lp->l_bp;
96 				maclcur->l_fp = lp->l_fp;
97 				free(lp);
98 			}
99 			if ((rep[0] == 'y' || rep[0] == 'Y') &&
100 			    (rep[1] == 'e' || rep[1] == 'E') &&
101 			    (rep[2] == 's' || rep[2] == 'S') &&
102 			    (rep[3] == '\0'))
103 				return (TRUE);
104 			if ((rep[0] == 'n' || rep[0] == 'N') &&
105 			    (rep[1] == 'o' || rep[0] == 'O') &&
106 			    (rep[2] == '\0'))
107 				return (FALSE);
108 		}
109 		rep = eread("Please answer yes or no.  %s? (yes or no) ",
110 		    buf, sizeof(buf), EFNUL | EFNEW | EFCR, sp);
111 	}
112 	/* NOTREACHED */
113 }
114 
115 /*
116  * This is the general "read input from the echo line" routine.  The basic
117  * idea is that the prompt string "prompt" is written to the echo line, and
118  * a one line reply is read back into the supplied "buf" (with maximum
119  * length "len").
120  * XXX: When checking for an empty return value, always check rep, *not* buf
121  * as buf may be freed in pathological cases.
122  */
123 /* VARARGS */
124 char *
125 eread(const char *fmt, char *buf, size_t nbuf, int flag, ...)
126 {
127 	va_list	 ap;
128 	char	*rep;
129 
130 	va_start(ap, flag);
131 	rep = veread(fmt, buf, nbuf, flag, ap);
132 	va_end(ap);
133 	return (rep);
134 }
135 
136 static char *
137 veread(const char *fp, char *buf, size_t nbuf, int flag, va_list ap)
138 {
139 	int	 dynbuf = (buf == NULL);
140 	int	 cpos, epos;		/* cursor, end position in buf */
141 	int	 c, i, y;
142 	int	 cplflag = FALSE;	/* display completion list */
143 	int	 cwin = FALSE;		/* completion list created */
144 	int	 mr = 0;		/* match left arrow */
145 	int	 ml = 0;		/* match right arrow */
146 	int	 esc = 0;		/* position in esc pattern */
147 	struct buffer	*bp;			/* completion list buffer */
148 	struct mgwin	*wp;			/* window for compl list */
149 	int	 match;			/* esc match found */
150 	int	 cc, rr;		/* saved ttcol, ttrow */
151 	char	*ret;			/* return value */
152 
153 	static char emptyval[] = "";	/* XXX hackish way to return err msg*/
154 
155 	if (inmacro) {
156 		if (dynbuf) {
157 			if ((buf = malloc(maclcur->l_used + 1)) == NULL)
158 				return (NULL);
159 		} else if (maclcur->l_used >= nbuf)
160 			return (NULL);
161 		bcopy(maclcur->l_text, buf, maclcur->l_used);
162 		buf[maclcur->l_used] = '\0';
163 		maclcur = maclcur->l_fp;
164 		return (buf);
165 	}
166 	epos = cpos = 0;
167 	ml = mr = esc = 0;
168 	cplflag = FALSE;
169 
170 	if ((flag & EFNEW) != 0 || ttrow != nrow - 1) {
171 		ttcolor(CTEXT);
172 		ttmove(nrow - 1, 0);
173 		epresf = TRUE;
174 	} else
175 		eputc(' ');
176 	eformat(fp, ap);
177 	if ((flag & EFDEF) != 0) {
178 		if (buf == NULL)
179 			return (NULL);
180 		eputs(buf);
181 		epos = cpos += strlen(buf);
182 	}
183 	tteeol();
184 	ttflush();
185 	for (;;) {
186 		c = getkey(FALSE);
187 		if ((flag & EFAUTO) != 0 && (c == ' ' || c == CCHR('I'))) {
188 			if (cplflag == TRUE) {
189 				complt_list(flag, buf, cpos);
190 				cwin = TRUE;
191 			} else if (complt(flag, c, buf, nbuf, epos, &i) == TRUE) {
192 				cplflag = TRUE;
193 				epos += i;
194 				cpos = epos;
195 			}
196 			continue;
197 		}
198 		cplflag = FALSE;
199 
200 		if (esc > 0) { /* ESC sequence started */
201 			match = 0;
202 			if (ml == esc && key_left[ml] && c == key_left[ml]) {
203 				match++;
204 				if (key_left[++ml] == '\0') {
205 					c = CCHR('B');
206 					esc = 0;
207 				}
208 			}
209 			if (mr == esc && key_right[mr] && c == key_right[mr]) {
210 				match++;
211 				if (key_right[++mr] == '\0') {
212 					c = CCHR('F');
213 					esc = 0;
214 				}
215 			}
216 			if (match == 0) {
217 				esc = 0;
218 				continue;
219 				/* hack. how do we know esc pattern is done? */
220 			}
221 			if (esc > 0) {
222 				esc++;
223 				continue;
224 			}
225 		}
226 		switch (c) {
227 		case CCHR('A'): /* start of line */
228 			while (cpos > 0) {
229 				if (ISCTRL(buf[--cpos]) != FALSE) {
230 					ttputc('\b');
231 					--ttcol;
232 				}
233 				ttputc('\b');
234 				--ttcol;
235 			}
236 			ttflush();
237 			break;
238 		case CCHR('D'):
239 			if (cpos != epos) {
240 				tteeol();
241 				y = buf[cpos];
242 				epos--;
243 				rr = ttrow;
244 				cc = ttcol;
245 				for (i = cpos; i < epos; i++) {
246 					buf[i] = buf[i + 1];
247 					eputc(buf[i]);
248 				}
249 				ttmove(rr, cc);
250 				ttflush();
251 			}
252 			break;
253 		case CCHR('E'): /* end of line */
254 			while (cpos < epos) {
255 				eputc(buf[cpos++]);
256 			}
257 			ttflush();
258 			break;
259 		case CCHR('B'): /* back */
260 			if (cpos > 0) {
261 				if (ISCTRL(buf[--cpos]) != FALSE) {
262 					ttputc('\b');
263 					--ttcol;
264 				}
265 				ttputc('\b');
266 				--ttcol;
267 				ttflush();
268 			}
269 			break;
270 		case CCHR('F'): /* forw */
271 			if (cpos < epos) {
272 				eputc(buf[cpos++]);
273 				ttflush();
274 			}
275 			break;
276 		case CCHR('Y'): /* yank from kill buffer */
277 			i = 0;
278 			while ((y = kremove(i++)) >= 0 && y != '\n') {
279 				int t;
280 				if (dynbuf && epos + 1 >= nbuf) {
281 					void *newp;
282 					size_t newsize = epos + epos + 16;
283 					if ((newp = realloc(buf, newsize))
284 					    == NULL)
285 						goto memfail;
286 					buf = newp;
287 					nbuf = newsize;
288 				}
289 				if (!dynbuf && epos + 1 >= nbuf) {
290 					ewprintf("Line too long");
291 					return (emptyval);
292 				}
293 				for (t = epos; t > cpos; t--)
294 					buf[t] = buf[t - 1];
295 				buf[cpos++] = (char)y;
296 				epos++;
297 				eputc((char)y);
298 				cc = ttcol;
299 				rr = ttrow;
300 				for (t = cpos; t < epos; t++)
301 					eputc(buf[t]);
302 				ttmove(rr, cc);
303 			}
304 			ttflush();
305 			break;
306 		case CCHR('K'): /* copy here-EOL to kill buffer */
307 			kdelete();
308 			for (i = cpos; i < epos; i++)
309 				kinsert(buf[i], KFORW);
310 			tteeol();
311 			epos = cpos;
312 			ttflush();
313 			break;
314 		case CCHR('['):
315 			ml = mr = esc = 1;
316 			break;
317 		case CCHR('J'):
318 			c = CCHR('M');
319 			/* FALLTHROUGH */
320 		case CCHR('M'):			/* return, done */
321 			/* if there's nothing in the minibuffer, abort */
322 			if (epos == 0 && !(flag & EFNUL)) {
323 				(void)ctrlg(FFRAND, 0);
324 				ttflush();
325 				return (NULL);
326 			}
327 			if ((flag & EFFUNC) != 0) {
328 				if (complt(flag, c, buf, nbuf, epos, &i)
329 				    == FALSE)
330 					continue;
331 				if (i > 0)
332 					epos += i;
333 			}
334 			buf[epos] = '\0';
335 			if ((flag & EFCR) != 0) {
336 				ttputc(CCHR('M'));
337 				ttflush();
338 			}
339 			if (macrodef) {
340 				struct line	*lp;
341 
342 				if ((lp = lalloc(cpos)) == NULL)
343 					goto memfail;
344 				lp->l_fp = maclcur->l_fp;
345 				maclcur->l_fp = lp;
346 				lp->l_bp = maclcur;
347 				maclcur = lp;
348 				bcopy(buf, lp->l_text, cpos);
349 			}
350 			ret = buf;
351 			goto done;
352 		case CCHR('G'):			/* bell, abort */
353 			eputc(CCHR('G'));
354 			(void)ctrlg(FFRAND, 0);
355 			ttflush();
356 			ret = NULL;
357 			goto done;
358 		case CCHR('H'):			/* rubout, erase */
359 		case CCHR('?'):
360 			if (cpos != 0) {
361 				y = buf[--cpos];
362 				epos--;
363 				ttputc('\b');
364 				ttcol--;
365 				if (ISCTRL(y) != FALSE) {
366 					ttputc('\b');
367 					ttcol--;
368 				}
369 				rr = ttrow;
370 				cc = ttcol;
371 				for (i = cpos; i < epos; i++) {
372 					buf[i] = buf[i + 1];
373 					eputc(buf[i]);
374 				}
375 				ttputc(' ');
376 				if (ISCTRL(y) != FALSE) {
377 					ttputc(' ');
378 					ttputc('\b');
379 				}
380 				ttputc('\b');
381 				ttmove(rr, cc);
382 				ttflush();
383 			}
384 			break;
385 		case CCHR('X'):			/* kill line */
386 		case CCHR('U'):
387 			while (cpos != 0) {
388 				ttputc('\b');
389 				ttputc(' ');
390 				ttputc('\b');
391 				--ttcol;
392 				if (ISCTRL(buf[--cpos]) != FALSE) {
393 					ttputc('\b');
394 					ttputc(' ');
395 					ttputc('\b');
396 					--ttcol;
397 				}
398 				epos--;
399 			}
400 			ttflush();
401 			break;
402 		case CCHR('W'):			/* kill to beginning of word */
403 			while ((cpos > 0) && !ISWORD(buf[cpos - 1])) {
404 				ttputc('\b');
405 				ttputc(' ');
406 				ttputc('\b');
407 				--ttcol;
408 				if (ISCTRL(buf[--cpos]) != FALSE) {
409 					ttputc('\b');
410 					ttputc(' ');
411 					ttputc('\b');
412 					--ttcol;
413 				}
414 				epos--;
415 			}
416 			while ((cpos > 0) && ISWORD(buf[cpos - 1])) {
417 				ttputc('\b');
418 				ttputc(' ');
419 				ttputc('\b');
420 				--ttcol;
421 				if (ISCTRL(buf[--cpos]) != FALSE) {
422 					ttputc('\b');
423 					ttputc(' ');
424 					ttputc('\b');
425 					--ttcol;
426 				}
427 				epos--;
428 			}
429 			ttflush();
430 			break;
431 		case CCHR('\\'):
432 		case CCHR('Q'):			/* quote next */
433 			c = getkey(FALSE);
434 			/* FALLTHROUGH */
435 		default:
436 			if (dynbuf && epos + 1 >= nbuf) {
437 				void *newp;
438 				size_t newsize = epos + epos + 16;
439 				if ((newp = realloc(buf, newsize)) == NULL)
440 					goto memfail;
441 				buf = newp;
442 				nbuf = newsize;
443 			}
444 			if (!dynbuf && epos + 1 >= nbuf) {
445 				ewprintf("Line too long");
446 				return (emptyval);
447 			}
448 			for (i = epos; i > cpos; i--)
449 				buf[i] = buf[i - 1];
450 			buf[cpos++] = (char)c;
451 			epos++;
452 			eputc((char)c);
453 			cc = ttcol;
454 			rr = ttrow;
455 			for (i = cpos; i < epos; i++)
456 				eputc(buf[i]);
457 			ttmove(rr, cc);
458 			ttflush();
459 		}
460 	}
461 done:
462 	if (cwin == TRUE) {
463 		/* blow away cpltion window */
464 		bp = bfind("*Completions*", TRUE);
465 		if ((wp = popbuf(bp, WEPHEM)) != NULL) {
466 			if (wp->w_flag & WEPHEM) {
467 				curwp = wp;
468 				delwind(FFRAND, 1);
469 			} else {
470 				killbuffer(bp);
471 			}
472 		}
473 	}
474 	return (ret);
475 memfail:
476 	if (dynbuf && buf)
477 		free(buf);
478 	ewprintf("Out of memory");
479 	return (emptyval);
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, WEPHEM);	/* 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 	if (inmacro)
773 		return;
774 
775 	va_start(ap, fmt);
776 	ttcolor(CTEXT);
777 	ttmove(nrow - 1, 0);
778 	eformat(fmt, ap);
779 	va_end(ap);
780 	tteeol();
781 	ttflush();
782 	epresf = TRUE;
783 }
784 
785 /*
786  * Printf style formatting. This is called by both "ewprintf" and "ereply"
787  * to provide formatting services to their clients.  The move to the start
788  * of the echo line, and the erase to the end of the echo line, is done by
789  * the caller.
790  * %c prints the "name" of the supplied character.
791  * %k prints the name of the current key (and takes no arguments).
792  * %d prints a decimal integer
793  * %o prints an octal integer
794  * %p prints a pointer
795  * %s prints a string
796  * %ld prints a long word
797  * Anything else is echoed verbatim
798  */
799 static void
800 eformat(const char *fp, va_list ap)
801 {
802 	char	kname[NKNAME], tmp[100], *cp;
803 	int	c;
804 
805 	while ((c = *fp++) != '\0') {
806 		if (c != '%')
807 			eputc(c);
808 		else {
809 			c = *fp++;
810 			switch (c) {
811 			case 'c':
812 				getkeyname(kname, sizeof(kname),
813 				    va_arg(ap, int));
814 				eputs(kname);
815 				break;
816 
817 			case 'k':
818 				for (cp = kname, c = 0; c < key.k_count; c++) {
819 					if (c)
820 						*cp++ = ' ';
821 					cp = getkeyname(cp, sizeof(kname) -
822 					    (cp - kname) - 1, key.k_chars[c]);
823 				}
824 				eputs(kname);
825 				break;
826 
827 			case 'd':
828 				eputi(va_arg(ap, int), 10);
829 				break;
830 
831 			case 'o':
832 				eputi(va_arg(ap, int), 8);
833 				break;
834 
835 			case 'p':
836 				snprintf(tmp, sizeof(tmp), "%p",
837 				    va_arg(ap, void *));
838 				eputs(tmp);
839 				break;
840 
841 			case 's':
842 				eputs(va_arg(ap, char *));
843 				break;
844 
845 			case 'l':
846 				/* explicit longword */
847 				c = *fp++;
848 				switch (c) {
849 				case 'd':
850 					eputl(va_arg(ap, long), 10);
851 					break;
852 				default:
853 					eputc(c);
854 					break;
855 				}
856 				break;
857 
858 			default:
859 				eputc(c);
860 			}
861 		}
862 	}
863 }
864 
865 /*
866  * Put integer, in radix "r".
867  */
868 static void
869 eputi(int i, int r)
870 {
871 	int	 q;
872 
873 	if (i < 0) {
874 		eputc('-');
875 		i = -i;
876 	}
877 	if ((q = i / r) != 0)
878 		eputi(q, r);
879 	eputc(i % r + '0');
880 }
881 
882 /*
883  * Put long, in radix "r".
884  */
885 static void
886 eputl(long l, int r)
887 {
888 	long	 q;
889 
890 	if (l < 0) {
891 		eputc('-');
892 		l = -l;
893 	}
894 	if ((q = l / r) != 0)
895 		eputl(q, r);
896 	eputc((int)(l % r) + '0');
897 }
898 
899 /*
900  * Put string.
901  */
902 static void
903 eputs(const char *s)
904 {
905 	int	 c;
906 
907 	while ((c = *s++) != '\0')
908 		eputc(c);
909 }
910 
911 /*
912  * Put character.  Watch for control characters, and for the line getting
913  * too long.
914  */
915 static void
916 eputc(char c)
917 {
918 	if (ttcol + 2 < ncol) {
919 		if (ISCTRL(c)) {
920 			eputc('^');
921 			c = CCHR(c);
922 		}
923 		ttputc(c);
924 		++ttcol;
925 	}
926 }
927 
928 void
929 free_file_list(struct list *lp)
930 {
931 	struct list	*next;
932 
933 	while (lp) {
934 		next = lp->l_next;
935 		free(lp->l_name);
936 		free(lp);
937 		lp = next;
938 	}
939 }
940 
941 static struct list *
942 copy_list(struct list *lp)
943 {
944 	struct list	*current, *last, *nxt;
945 
946 	last = NULL;
947 	while (lp) {
948 		current = malloc(sizeof(struct list));
949 		if (current == NULL) {
950 			/* Free what we have allocated so far */
951 			for (current = last; current; current = nxt) {
952 				nxt = current->l_next;
953 				free(current->l_name);
954 				free(current);
955 			}
956 			return (NULL);
957 		}
958 		current->l_next = last;
959 		current->l_name = strdup(lp->l_name);
960 		last = current;
961 		lp = lp->l_next;
962 	}
963 	return (last);
964 }
965