/**************************************************************
 *
 *	CRISP - Custom Reduced Instruction Set Programmers Editor
 *
 *	(C) Paul Fox, 1989, 1990, 1991
 *
 *    Please See COPYLEFT notice.
 *
 **************************************************************/

# include        "list.h"
# include	"alt.h"
# include	<time.h>

# define	EBUFSIZ	512

# define	E_LINE		0x01	/* Line: ..			*/
# define	E_COL		0x02	/* Col: ..			*/
# define	E_PERCENT	0x04	/* nn%				*/
# define	E_TIME		0x08	/* hh:mm a/pm			*/
# define	E_REMEMBER	0x10	/* RE / PA String.		*/
# define	E_CURSOR	0x20	/* IN / OV cursor type. 	*/
int	echo_flags = E_CURSOR | E_LINE | E_COL | E_REMEMBER | E_TIME;

# undef	ARG_LIST	/* Defined in list.h */
# define	ARG_LIST	x1, x2, x3, x4, x5, x6, x7, x8, x9, x10
# define	LSIZE		ncol	/* Echo line size.		*/
# define	LCOL		(LSIZE - 31)
					/* Position of 'Line: ..'	*/

/**********************************************************************/
/*   Column  where  cursor  is  on  status line. Needed by display.c  */
/*   because  asynchronous  pty  input  may  move  the  cursor so it  */
/*   needs to know where to put it back.			      */
/**********************************************************************/
int	echo_col;
char	*echo_line;
int	prompting = FALSE;
int	prompt_len = 0;			/* Length of prompt - so we can skip */
					/* prompt in (inq_cmd_line).	*/
int	pcolor = CMESSAGE;	/* Used by (error) */
int	lc_column;		/* Column where Line/Col message starts. */
char	*cmd_line_ptr;		/* Pointer to string just typed in by user */
				/* Needed by inq_cmd_line() primitve.	*/
extern	int	imode;
extern vbyte_t **vscreen;
extern vbyte_t **pscreen;
extern int display_enabled;
extern	ref_t	*push_ref;
int	pchar_buf[10];		/* Printable character buffer. */
char hex_digits[] = "0123456789ABCDEF";
/**********************************************************************/
/*   Keep  first  64  bytes of last message printed. We can optimise  */
/*   output  if  user  keeps printing same message by checking first  */
/*   MSG_SIZE bytes of each message to see if there is a difference.  */
/**********************************************************************/
# define	MSG_SIZE	64

/**********************************************************************/
/*   Last  message  printed.  Accessed  by  ereply  so we can zap it  */
/*   when user is typing in on command line.			      */
/**********************************************************************/
char last_msg[MSG_SIZE];

/**********************************************************************/
/*   Prototypes							      */
/**********************************************************************/
void	print_cursor();
int	ereply1();
int	ereply2();
void	position_prompt PROTO((char *, int, int, int *));
int	estrlen();
void	inq_message();
void	inq_cmd_line();
void	ewprintf();
void	ewputs();
void	update_bottom_line PROTO((int));
vbyte_t	*e_putc PROTO((vbyte_t *, int));
vbyte_t	*e_putc1 PROTO((vbyte_t *, int));
vbyte_t *e_putc2 PROTO((vbyte_t *, int *, int, int));
void	line_col();
void	set_echo_line();
void	ewputs();
/*
 * Ask "yes" or "no" question.
 * Return ABORT if the user answers the question
 * with the abort ("^G") character. Return FALSE
 * for "no" and TRUE for "yes". No formatting
 * services are available. No newline required.
 */
int
eyorn(sp)
char *sp;
{
	register KEY    s;

	while (1) {
		ewprintf("%s [yn] ? ", sp);
		s = getkey((long) 0);
		if (strchr("yYnN\033", s))
			break;
		}
	ewprintf("");
	switch (s) {
	  case 'y':
	  case 'Y':
	  	return TRUE;
	  case 'n':
	  case 'N':
	  	return FALSE;
	  default:
	  	return ABORT;
	  }
}

/*
 * Like eyorn, but for more important question. User must type either all of
 * "yes" or "no", and the trainling newline.
 */
int
eyesno(sp) 
char *sp; 
{
	register int    s;
	char            buf[64];
	char		msg[256];
	
	sprintf(msg, "%s? (yes or no)", sp);
	s = ereply(msg, buf, sizeof(buf));
	for (;;) {
		if (s == ABORT) return ABORT;
		if (s != FALSE) {
			if ((buf[0] == 'y' || buf[0] == 'Y')
			&&  (buf[1] == 'e' || buf[1] == 'E')
			&&  (buf[2] == 's' || buf[2] == 'S')) return TRUE;
			if ((buf[0] == 'n' || buf[0] == 'N')
			&&  (buf[1] == 'o' || buf[0] == 'O')) return FALSE;
		}
		sprintf(msg, "Please answer yes or no.  %s? (yes or no) ", sp);
		s = ereply(msg, buf, sizeof(buf));
	}
}
void
print_cursor(insert_mode)
int	insert_mode;
{	extern int virtual_space;
	static int old_mode = -2;
	static int old_space = -2;

	if (scrfn.scr_cursor == NULL && pt.pt_icursor[0] == NULL)
		return;
	set_hooked();
	current_offset(curwp->w_col, FALSE);
	if (old_space == virtual_space && insert_mode == old_mode)
		return;

	if (scrfn.scr_cursor)
		(*scrfn.scr_cursor)(insert_mode, virtual_space);
	else if (insert_mode)
		putpad(virtual_space ? pt.pt_vicursor : pt.pt_icursor);
	else
		putpad(virtual_space ? pt.pt_vocursor : pt.pt_ocursor);
	old_mode = insert_mode;
	old_space = virtual_space;
}
int
ereply(prompt, buf, nbuf) 
char	*prompt;
char	*buf;
int	nbuf;
{
	return ereply1(prompt, (char *) NULL, buf, nbuf);
}
int
edefreply(prompt, defstr, buf, nbuf) 
char	*prompt;
char	*defstr;
char	*buf;
int	nbuf;
{

	return ereply1(prompt, defstr, buf, nbuf);
}
int
ereply1(fp, defstr, buf, nbuf) 
char	*fp;
char	*defstr;
char	*buf;
int	nbuf;
{	int	ret;
	char	pbuf[EBUFSIZ + 20];
	extern int dflag;
	int	saved_dflag = dflag;
	int	dflag1 = dflag;
	int	ml = msg_level;
	
	if (msg_level == 0)
		msg_level = 1;

	prompt_len = estrlen(fp);
	ewputs(fp, defstr);
	/***********************************************/
	/*   Dont  bother  saving  command history if  */
	/*   we got a one character response buffer.   */
	/***********************************************/
	if (nbuf > 1) {
		if (dflag && (dflag & DB_PROMPT) == 0)
			dflag1 = 0;

		sprintf(pbuf, "_prompt_begin \"%s\"", fp);

		dflag = dflag1;
		str_exec(pbuf);
		dflag = saved_dflag;
		}

	ret = ereply2(fp, defstr, buf, nbuf);
	
	if (nbuf > 1) {
		dflag = dflag1;
		/***********************************************/
		/*   Save  a  global  pointer to the typed in  */
		/*   text  so  that  inq_cmd_line()  can  get  */
		/*   the whole command string.		       */
		/***********************************************/
		cmd_line_ptr = buf;
		str_exec("_prompt_end");
		/***********************************************/
		/*   Set    pointer    to    NULL   so   that  */
		/*   inq_cmd_line()   only  works  partially,  */
		/*   i.e.   it   can  only  get  the  bit  on  */
		/*   display, and not the full string.	       */
		/***********************************************/
		cmd_line_ptr = NULL;
		}

	msg_level = ml;
	set_hooked();

	dflag = saved_dflag;
	return ret;

}
int
ereply2(prompt, defstr, buf, nbuf) 
char  *prompt;
char  *defstr;
char  *buf; 
int	nbuf;
{	register int bpos;
	register KEY c, t;
	int	startcol = estrlen(prompt);
	int     insert_mode = TRUE;
	char    *cp;
	int     first_key = TRUE;
	int     left = 0;
	char	sacc[80];

	last_msg[0] = NULL;
	prompting = TRUE;
	print_cursor(insert_mode);
	bpos = 0;
	buf[0] = NULL;
	if (defstr == NULL)
		defstr = "";
	strcpy(buf, defstr);
	flush_col_cache();

	while (1) {
		if (!first_key)
			position_prompt(buf, startcol, bpos, &left);
		c = getkey((long) 0);
		/***********************************************/
		/*   If  this  is  the  first  key  and its a  */
		/*   special   one,   then   user   must   be  */
		/*   accepting  the  default  prompt value so  */
		/*   we need to redraw it unhighlited.	       */
		/***********************************************/
		if (first_key && 
		    (c == 0x7f || c == CTRL_H || c == KEY_DEL ||
		    c == KEY_WLEFT || c == KEY_WRIGHT || 
		    c == KEY_HOME || c == KEY_END ||
		    c == KEY_LEFT || c == KEY_RIGHT)) {
			if (nbuf == 1) {
		        	buf[0] = (char) c;
			        buf[1] = NULL;
			        prompting = FALSE;
			        return TRUE;
		        	}
			strcpy(buf, defstr);
			bpos = strlen(buf);
			}
		else if (first_key && c != 0x0D) {
			/***********************************************/
			/*   If  this  is the first key and user isnt  */
			/*   accepting  it,  then  erase  the default  */
			/*   value from the screen.		       */
			/***********************************************/
			bpos = 0;
			buf[0] = NULL;
			}
		defstr = "";
		first_key = FALSE;
		/***********************************************/
		/*   One     character     reads    termiante  */
		/*   straightaway   after  a  single  non-ESC  */
		/*   character is typed.		       */
		/***********************************************/
		if (nbuf == 1 && c != 0x1b) {
			buf[0] = (char) c;
			buf[1] = NULL;
			goto done;
			}
		/***********************************************/
		/*   If   we   have  a  16-bit  keycode  then  */
		/*   pretend  user  hit  tab so we get to the  */
		/*   right case branch.			       */
		/***********************************************/
		t = c;
		if (t & ~0xff)
			t = '\t';
		switch (c) {
		  case '\r':
		  case '\n':
			goto done;
	
		  case ALT_H:
			prompting = FALSE;
			trigger(REG_ALT_H);
			prompting = TRUE;
			break;
		  case '\033':
cancel:
			print_cursor(imode);
			ewprintf("Command cancelled.");
			prompting = FALSE;
			return (ABORT);
	
		  case '\t':
		  case ALT_L:
		  case KEY_DOWN:
		  case KEY_UP:
			push_back1(push_ref, c);
			trigger(REG_INVALID);
			prompting = FALSE;
			strcpy(echo_line + prompt_len, buf);
			str_exec("_bad_key");
		   	prompting = TRUE;
			if ((defstr = acc_get_sval()) == NULL)
				goto cancel;
			ewputs(prompt, defstr);
			strncpy(buf, defstr, nbuf);
			/***********************************************/
			/*   Keep  a  private copy of the accumulator  */
			/*   because  the  demo  macro can destroy it  */
			/*   for us.				       */
			/***********************************************/
			strncpy(sacc, defstr, sizeof sacc);
			defstr = sacc;
			first_key = TRUE;
			continue;
	
		  case KEY_WLEFT:
			while (isspace(buf[bpos]) && bpos > 0)
				bpos--;
			while (!isspace(buf[bpos]) && bpos > 0)
				bpos--;
			break;
		  case KEY_WRIGHT:
			while (isspace(buf[bpos]) && buf[bpos])
				bpos++;
			while (!isspace(buf[bpos]) && buf[bpos])
				bpos++;
			break;
		  case KEY_RIGHT:
			if (buf[bpos])
				++bpos;
			break;
		  case KEY_LEFT:
			if (bpos > 0)
				--bpos;
			break;
		  case KEY_HOME:
		  	bpos = 0;
			break;
		  case KEY_END:
		  	bpos = strlen(buf);
			break;
		  case ALT_I:
			insert_mode = !insert_mode;
			print_cursor(insert_mode);
			ttflush();
			break;
			
		  case CCHR('H'):
		  	/***********************************************/
		  	/*   Delete previous character.		       */
		  	/***********************************************/
		  	if (bpos > 0) {
				bpos--;
				strcpy(buf + bpos, buf + bpos + 1);
				}
			break;
		  case 0x7F:
		  case KEY_DEL:
		  	/***********************************************/
		  	/*   Delete character under the cursor.	       */
		  	/***********************************************/
			if (buf[bpos])
				strcpy(buf + bpos, buf + bpos + 1);
			break;
			
		  case ALT_K:
		  	/***********************************************/
		  	/*   Delete characters to end of input.	       */
		  	/***********************************************/
			buf[bpos] = NULL;
			break;
			
		  case ALT_D:
		  case CCHR('X'):
		  case CCHR('U'):
		  	bpos = 0;
			buf[0] = NULL;
			break;
	
		  case CCHR('Q'):
		  case ALT_Q:
		  	/***********************************************/
		  	/*   Quote the next input character.	       */
		  	/***********************************************/
			c = get_rawkey((long) 0L);
			/* Fallthru... */
		  default:
		  	/***********************************************/
		  	/*   Make sure we got room in buffer.	       */
		  	/***********************************************/
			if (estrlen(buf) >= nbuf-1) {
				ttbeep();
				continue;
				}
			/***********************************************/
			/*   If  in  insert  mode,  then  shuffle  up  */
			/*   characters to the right of the cursor.    */
			/***********************************************/
			if (insert_mode) {
				char    buf1[EBUFSIZ];
				strcpy(buf1, buf+bpos);
				strcpy(buf+bpos+1, buf1);
				}
			else if (buf[bpos] == NULL) {
				/***********************************************/
				/*   We're  in  overtype  mode,  so make sure  */
				/*   next  when  overtyping at the end of the  */
				/*   input we always have a NULL at the end.   */
				/***********************************************/
				buf[bpos+1] = NULL;
				}
			/***********************************************/
			/*   Stuff  the  character  in  and increment  */
			/*   the current buffer pointer position.      */
			/***********************************************/
			cp = buf + bpos++;
			*cp = (char) c;
			break;
		  }
		}
done:
	prompting = FALSE;
	print_cursor(imode);
	return TRUE;
}

/**********************************************************************/
/*   Function  to  display  the status line with the users input and  */
/*   any default which may be highlited.			      */
/**********************************************************************/
void
position_prompt(buf, startcol, bpos, left)
char	*buf;
int	startcol;
int	bpos;
int	*left;
{	register vbyte_t	*pp = vscreen[nrow-1];
	vbyte_t		*pp_end;
	int		pos, j;
	register int 	i;
	int	partial = 0;
	int	attr;
	
	pp_end = pp + lc_column - 1;
	pp += startcol;
	
	/***********************************************/
	/*   Figure  out  where  the  cursor is going  */
	/*   to land.				       */
	/***********************************************/
	for (pos = 0, i = 0; i < bpos && buf[i]; )
		pos += printable_char(buf[i++]);
	/***********************************************/
	/*   If  cursor  off  the screen then we need  */
	/*   to reframe the users input.	       */
	/***********************************************/
	if (bpos < *left) {
		while (*left > bpos) {
			pos -= printable_char(buf[--i]);
			(*left)--;
			}
		}
	else if (startcol + pos - *left >= lc_column-1) {
		pos = lc_column - 1;
		i--;
		while (pos > startcol && i >= 0) {
			pos -= printable_char(buf[i--]);
			}
		i++;
		if (pos < startcol) {
			partial = startcol - pos;
			}
		i++;
		*left = i;
		}
	/***********************************************/
	/*   Now  redraw  the line. Pad with trailing  */
	/*   spaces.				       */
	/***********************************************/
	buf += *left;
	attr = FG(col_table.c_messages) | BG(col_table.c_background);
	for (i = *left; pp < pp_end; i++) {
		int	ch = *buf ? *buf++ : ' ';
		if (i == bpos)
			echo_col = pp - vscreen[nrow-1];
		j = printable_char(ch);
		pp = e_putc2(pp, pchar_buf + partial, 
			j - partial, attr);
		partial = 0;
		}
	update_bottom_line(echo_col);
}
int
estrlen(str)
register char *str;
{	register int	len = 0;

	if (str) {
		while (*str) {
			char ch = *str++;
			len += printable_char(ch >= ' ' ? ch : (ch | 0x80));
			}
		}
	return len;

}
void
inq_message()
{
	acc_assign_str(echo_line, -1);
}
void
inq_cmd_line()
{
	if (cmd_line_ptr)
		acc_assign_str(cmd_line_ptr, -1);
	else
		acc_assign_str(echo_line + prompt_len, -1);
}
/**********************************************************************/
/*   Display a printf-style string on the status line.		      */
/**********************************************************************/
/* VARARGS1 */
void
ewprintf(str, ARG_LIST)
char	*str;
int	ARG_LIST;
{	unsigned char	buf[EBUFSIZ];

	sprintf((char *) buf, str, ARG_LIST);
	ewputs((char *) buf, (char *) NULL);
}
/* VARARGS1 */
void
ewputs(str, defstr)
char	*str;
char	*defstr;
{
	register char *cp;
	vbyte_t	*pp, *ppend;
	int	space;
	
	/***********************************************/
	/*   If    display   not   been   initialised  */
	/*   properly   then   force   the   line/col  */
	/*   fields   out  so  that  lc_column  knows  */
	/*   where to stop.			       */
	/***********************************************/
	if (lc_column == 0)	
		line_col(TRUE);
	if (echo_line == NULL) {
		write(1, str, strlen(str));
		write(1, "\r\n", 2);
		return;
		}
	/***********************************************/
	/*   If  we  have a default prompt, then dont  */
	/*   try and optimise.			       */
	/***********************************************/
	if (defstr != NULL)
		last_msg[0] = NULL;
	else if (strcmp(last_msg, str) == 0 && str[0])
		return;
	else {
		strncpy(last_msg, str, sizeof last_msg - 1);
		}
	
	if (lc_column > 0) {
		strncpy(echo_line, str, lc_column-1);
		echo_line[lc_column-1] = NULL;
		}

	pp = vscreen[nrow-1];
	ppend = pp + lc_column - 1;
	for (cp = str; *cp; ) {
		if (lc_column && pp >= ppend)
			break;
		pp = e_putc1(pp, *cp++);
		}


	if (defstr && *defstr) {
		int color = FG(col_table.c_fg) | BG(col_table.c_bg);
		strcat(echo_line, defstr);
		for (cp = defstr; *cp && pp < ppend; cp++) {
			pp = e_putc(pp, *cp | color);
			}
		}
	echo_col = pp - vscreen[nrow-1];
	space = ' ' | BG(col_table.c_background) | FG(col_table.c_normal);
	while (pp < ppend)
		pp = e_putc(pp, space);
	update_bottom_line(echo_col);
}
vbyte_t *
e_putc1(pp, c)
vbyte_t	*pp;
int	c;
{
	int	color;
	
	if (pcolor == CMESSAGE)
		color = col_table.c_messages;
	else
		color = col_table.c_error;
	return e_putc(pp, c | FG(color) | BG(col_table.c_background));
}
vbyte_t *
e_putc(pp, c)
vbyte_t	*pp;
int	c;
{
	int	hi_byte = c & COLOR_MASK;
	register int	i;

	trace_log("%c", c);
	if (c == '\r' || c == '\n')
		return pp;

	i = printable_char(c);
	return e_putc2(pp, pchar_buf, i, hi_byte);
}
vbyte_t *
e_putc2(pp, ip, len, attr)
vbyte_t	*pp;
int	*ip;
int	len;
int	attr;
{
	vbyte_t	*ppend;

	ppend = vscreen[nrow - 1] + lc_column - 1;
	while (len-- > 0 && pp < ppend) {
		*pp++ = (vbyte_t) (*ip++ | attr);
		}
	return pp;
}
void
line_col(force)
int	force;
{
	char	line_buf[64];
	static char old_line_buf[64];
	char	*cp;
	struct tm *tp;
	extern long time();
	long	timl;
	static	int	hours = -1;
	static	int	minutes = -1;
	static int	old_line = -1;
	static int	old_col = -1;
	static char	xx[3];
	static	char	*old_rem_string = xx;
	extern	int	imode;
	extern char *rem_string;
	int	l = 0;
	int	c = 0;
	long	perc;
	vbyte_t	*pp;

	if (curwp) {
		l = curwp->w_line;
		c = curwp->w_col;
		}
	/***********************************************/
	/*   If  we've  been  forced  to  update  the  */
	/*   screen  then  make  sure  that  we think  */
	/*   everythings    change   to   force   the  */
	/*   updating.   This   occurs  for  example,  */
	/*   when the screen is redrawn.	       */
	/***********************************************/
	if (force) {
		old_col = old_line = hours = minutes = -1;
		old_rem_string = xx;
		old_line_buf[0] = NULL;
		}
	timl = time((long *) 0);
	tp = localtime(&timl);
	if (c == old_col && l == old_line &&
		tp->tm_hour == hours && tp->tm_min == minutes &&
		*rem_string == *old_rem_string)
		return;

	cp = line_buf;
	*cp = NULL;
	if (echo_flags & E_LINE) {
		sprintf(cp, l > 9999 ? "Line:%-5u " : "Line: %-4u ", l);
		cp += 10;
		cp += strlen(cp);
		}
	if (echo_flags & E_COL) {
		sprintf(cp, c > 99 ? "Col:%-3u " : "Col: %-2u ", c);
		cp += 7;
		cp += strlen(cp);
		}
	perc = ((long) l * 100L) / (long) (curbp ? curbp->b_numlines : 1);
	if (perc > 100)
		perc = 100;
	if (echo_flags & E_PERCENT) {
		if (perc >= 100)
			strcpy(cp, "END ");
		else
			sprintf(cp, "%2lu%% ", perc);
		cp += strlen(cp);
		}
	if (echo_flags & E_CURSOR && pt.pt_icursor[0] == NULL) {
		if (imode == FALSE) {
			*cp++ = 'O';
			*cp++ = 'V';
			*cp++ = ' ';
			*cp = NULL;
			}
		}
	if (echo_flags & E_REMEMBER && rem_string[0] != ' ') {
		strcpy(cp, rem_string);
		cp += strlen(cp);
		*cp++ = ' ';
		*cp = NULL;
		}

	if (echo_flags & E_TIME) {
		sprintf(cp, "%d:%02d %cm",
			tp->tm_hour > 12 ? tp->tm_hour - 12 :
			tp->tm_hour == 0 ? 12 : tp->tm_hour,
			tp->tm_min, tp->tm_hour >= 12 ? 'p' : 'a');
		cp += strlen(cp);
		}

	
	/***********************************************/
	/*   Remember     the    old    values    for  */
	/*   optimisation.			       */
	/***********************************************/
	hours = tp->tm_hour;
	minutes = tp->tm_min;
	old_line = l;
	old_col = c;
	strcpy(old_rem_string, rem_string);

	/***********************************************/
	/*   Set  pp  to point to the internal buffer  */
	/*   containing  what  we  want on the screen  */
	/*   (as  opposed  to  pscreen  which is what  */
	/*   actually is on the screen).	       */
	/***********************************************/
	pp = vscreen[nrow - 1];
	/***********************************************/
	/*   If  last  line/col  not  at  same column  */
	/*   position   then  just  print  the  whole  */
	/*   string.				       */
	/***********************************************/
	l = ncol - 1 - strlen(line_buf);

	{int	i;
	int	attr = FG(col_table.c_normal) | BG(col_table.c_background);
	int	space = attr | ' ';

	/***********************************************/
	/*   Erase  characters  which  no longer need  */
	/*   to be shown.			       */
	/***********************************************/
	if (lc_column < l) {
		pp += lc_column;
		for (i = lc_column; i < l; i++)
			*pp++ = space;
		}
	else
		pp += l;
		
	/***********************************************/
	/*   Now draw in the line/col string.	       */
	/***********************************************/
	for (cp = line_buf; *cp; )
		*pp++ = attr | *cp++;
	/***********************************************/
	/*   Call   update_line  to  actually  update  */
	/*   the screen.			       */
	/***********************************************/
	update_bottom_line(-1);
	}
	strcpy(old_line_buf, line_buf);
	lc_column = l;
}
void
update_bottom_line(col)
int	col;
{	int	i = nrow - 1;
	uline(i, vscreen[i], pscreen[i]);
	ucopy(vscreen[i], pscreen[i]);
	if (col >= 0) {
		ttmove(i, col);
		prompting++;
		set_cursor();
		prompting--;
		}
	ttflush();
}
void
set_echo_line()
{
	acc_assign_int((long) echo_flags);
	if (argv[1].l_flags != F_NULL) {
		echo_flags = argv[1].l_int;
		if (display_enabled)
			line_col(TRUE);
		}
}
/**********************************************************************/
/*   Function  to  print  a  message  with  a  filename  in  it, but  */
/*   truncate  the  filename  if  its  too  long  to fit on the echo  */
/*   line.  The  format  argument  must  be a sprintf() style string  */
/*   with TWO %s formats in it.					      */
/**********************************************************************/
void
infof_truncated(fmt, filename)
char	*fmt;
char	*filename;
{	extern int lc_column;
	char	*dots = "";

	/***********************************************/
	/*   If   filename   is   very   long,   then  */
	/*   truncate  it  a  bit  so that we can see  */
	/*   it  and  the  percentage  on  the status  */
	/*   line.				       */
	/***********************************************/
	if (lc_column) {
		int	len = strlen(fmt) - 2 + strlen(filename);
		if (len >= lc_column) {
			filename += len - lc_column + 3;
			dots = "...";
			}
		}
	infof(fmt, dots, filename);
}
/**********************************************************************/
/*   Function  to  convert  a character to a printable format taking  */
/*   into  account  whether the terminal can support printable 8-bit  */
/*   chars,  etc.  Returns  number  of  characters  in  string to be  */
/*   printed.							      */
/**********************************************************************/
int
printable_char(c1)
int	c1;
{	int	attr = c1 & ~0xff;
	extern cmap_t *base_cmap;
	register int i;
	int	len = base_cmap->cm_length[c1 & 0xff];
	unsigned char	*cp = (unsigned char *) base_cmap->cm_str[c1 & 0xff];
	
	for (i = 0; i < len; )
		pchar_buf[i++] = attr | *cp++;
	return len;
}
/**********************************************************************/
/*   Function  to  redisplay  the  echo line. We do this when screen  */
/*   is  redrawn  because  the  window  got bigger. Unfortunately we  */
/*   lose the attribute info, but at least we display the prompt.     */
/**********************************************************************/
void
redraw_echo_line()
{	register char *cp;
	vbyte_t	*pp = vscreen[nrow-1];
	vbyte_t	*ppend = pp + lc_column - 1;

	if (echo_line == NULL)
		return;
	/***********************************************/
	/*   Force   the   space   before  the  Line:  */
	/*   prompt to be filled in.		       */
	/***********************************************/
	lc_column++;
	for (cp = echo_line; pp <= ppend; )
		pp = e_putc1(pp, *cp ? *cp++ : ' ');
	lc_column--;
}
