
/*
   input editor for interactive streams.  this should get replaced
   when we have more intelligient underlying streams...
*/

#include "io-defs.h"
#include "buckybits.h"

/*
   helper fun for displaying partial line.
*/
local redisplay(s, buf, start, space, fun)
struct streamoid * s;
char * buf;
int start;				/* start offset in fun */
int space;				/* if draw space at end */
int (* fun)();				/* display_char fun */
{
  char * p = buf + start;
  int n = 0;				/* n chars displayed */
  
  while (*p)
	{
	(*fun)(s, *p++);
	++n;
	}
  if (space)
	{
	(*fun)(s, ' ');
	++n;
	}
  while (n-- > 0)
	(*fun)(s, '\b');
}

int __input_editor(s, buf, nbytes_buf, get_char_fun, display_char_fun)
struct streamoid * s;			/* streamoid we're using */
char * buf;				/* buf to fill */
int nbytes_buf;				/* max size */
int (* get_char_fun)();			/* fun to apply to stream for char */
int (* display_char_fun)();		/* fun to apply to s, char */
{
/* for now, just do a few simple things */
  int ch;				/* char we read from stream */
  int nbytes;				/* nbytes valid in buf now */
  int i, j;				/* idx in buf */
  char * p;
  int done = 0;

  nbytes = strlen(buf);
/* display the string */
  for (p = buf ; *p ; p++)
	(*display_char_fun)(s, *p);
  i = nbytes;
  for ( ; !done ; )
	{
	ch = (*get_char_fun)(s);
/* kludge for ^Z */
	if (ch == 0x1A)
		ch = EOF_VALUE;
	switch(ch)
		{
		case EOF_VALUE:
		case '\r':
		case '\n':
			done++;
			break;

		case 0x08:		/* backspace */
		case 0x7F:
			if (i > 0)	/* anything to rub out? */
				{
/* this case is kludged for brain-dead ST console */
				if (ch == 0x7F)
					{
					(*display_char_fun)(s, '\b');
					(*display_char_fun)(s, ' ');
					(*display_char_fun)(s, '\b');
					(*display_char_fun)(s, '\b');
					}
/* do the real rubout */
				(*display_char_fun)(s, '\b');
				--i;
				strcpy(buf + i, buf + i + 1);
				--nbytes;
				redisplay(s, buf, i, 1, display_char_fun);
				}
			break;

		case 0x00:		/* nul? */
			break;		/* just ignore it */
		case 0x01:		/* ^A.  go to bol */
			while (i)
				{
				(*display_char_fun)(s, '\b');
				--i;
				}
			break;
		case 0x02:		/* ^B */
			if (i)
				{
				(*display_char_fun)(s, '\b');
				--i;
				}
			break;
		case 0x03:		/* ^C */
			break;
		case 0x04:		/* ^D */
			if (i < nbytes)
				{
				strcpy(buf + i, buf + i + 1);
				--nbytes;
				redisplay(s, buf, i, 1, display_char_fun);
				}
			break;
		case 0x05:		/* ^E */
			while (i < nbytes)
				{
				(*display_char_fun)(s, buf[i]);
				++i;
				}
			break;
		case 0x06:		/* ^F */
			if (i < nbytes)	
				{
				(*display_char_fun)(s, buf[i]);
				++i;
				}
			break;
		case 0x07:
		case 0x09:		/* tab?!? */
			(*display_char_fun)(s, 0x07);
			break;
		case 0x0B: break;
		case 0x0C:		/* ^L */
			for (j = i ; j > 0 ; j--)
				(* display_char_fun)(s, '\b');
			for (j = 0 ; j < nbytes ; j++)
				(* display_char_fun)(s, buf[j]);
			for (j = nbytes ; j > i ; j--)
				(* display_char_fun)(s, '\b');
			break;
		case 0x0E: case 0x0F: case 0x10: case 0x11:
		case 0x12: case 0x13: case 0x14: case 0x15:
		case 0x16: case 0x17: case 0x18: case 0x19:
			break;
		/* more later... */
		default:
			for (j = nbytes ; j > i - 1 ; j--)
				buf[j + 1] = buf[j];
			nbytes++;
			buf[i++] = ch;
			redisplay(s, buf, i, 0, display_char_fun);
			if (nbytes + 1 >= nbytes_buf)
				done++;
			break;
		}			/* done dispatching on chars */		
	}
  return(ch);				/* return terminating char */
}

