/* SLang_read_line interface --- uses SLang tty stuff */
/* Copyright (c) 1992, 1995 John E. Davis
 * All rights reserved.
 * 
 * You may distribute under the terms of either the GNU General Public
 * License or the Perl Artistic License.
 */


#include "config.h"

#include <stdio.h>


#include "slang.h"
#include "_slang.h"

#ifdef REAL_UNIX_SYSTEM
int SLang_RL_EOF_Char = 4;
#else
int SLang_RL_EOF_Char = 26;
#endif

int SLang_Rline_Quit;
static SLang_RLine_Info_Type *This_RLI;

static unsigned char Char_Widths[256];
static void position_cursor (int);

static void rl_beep (void)
{
   putc(7, stdout);
   fflush (stdout);
}

/* editing functions */
static int rl_bol (void)
{
   if (This_RLI->point == 0) return 0;
   This_RLI->point = 0;
   return 1;
}

static int rl_eol (void)
{
   if (This_RLI->point == This_RLI->len) return 0;
   This_RLI->point = This_RLI->len;
   return 1;
}

static int rl_right (void)
{
   if (This_RLI->point == This_RLI->len) return 0;
   This_RLI->point++;
   return 1;
}

static int rl_left (void)
{
   if (This_RLI->point == 0) return 0;
   This_RLI->point--; 
   return 1;
}

static int rl_self_insert (void)
{
   unsigned char *pmin, *p;
   
   if (This_RLI->len == This_RLI->buf_len)
     {
	rl_beep ();
	return 0;
     }
   
   pmin = This_RLI->buf + This_RLI->point;
   p = This_RLI->buf + This_RLI->len;
   while (p > pmin) 
     {
	*p = *(p - 1);
	p--;
     }
   *pmin = SLang_Last_Key_Char;
   
   This_RLI->len++;
   This_RLI->point++;
   if ((This_RLI->curs_pos + 2 >= This_RLI->edit_width)
       || (This_RLI->tt_insert == NULL)
       || (Char_Widths[SLang_Last_Key_Char] != 1)) return 1;
   
   (*This_RLI->tt_insert)((char) SLang_Last_Key_Char);
   /* update screen buf */
   p = This_RLI->old_upd + (This_RLI->len - 1);
   pmin = This_RLI->old_upd + (This_RLI->point - 1);
   while (p > pmin) 
     {
	*p = *(p - 1);
	p--;
     }
   *pmin = SLang_Last_Key_Char;
   return 0;
}

int SLang_rline_insert (char *s)
{
   unsigned char *pmin, *p;
   int n;
   
   n = strlen (s);
   if (n > This_RLI->buf_len - This_RLI->len) 
     n = This_RLI->buf_len - This_RLI->len;
   
   if (n == 0) return 0;
   
   pmin = This_RLI->buf + This_RLI->point;
   p = This_RLI->buf + (This_RLI->len - 1);
   
   while (p >= pmin)
     {
	*(p + n) = *p;
	p--;
     }
   SLMEMCPY ((char *) pmin, s, n);
   
   This_RLI->len += n;
   This_RLI->point += n;
   return n;
}


static int rl_deln (int n)
{
   unsigned char *pmax, *p;
   
   p = This_RLI->buf + This_RLI->point;
   pmax = This_RLI->buf + This_RLI->len;
   
   if (p + n > pmax) n = (int) (pmax - p);
   while (p < pmax) 
     {
	*p = *(p + n);
	p++;
     }
   This_RLI->len -= n;
   return n;
}

static int rl_del (void)
{
   return rl_deln(1);
}

static int rl_quote_insert (void)
{
   int err = SLang_Error;
   SLang_Error = 0;
   SLang_Last_Key_Char = (*This_RLI->getkey)();
   rl_self_insert ();
   if (SLang_Error == USER_BREAK) SLang_Error = 0;
   else SLang_Error = err;
   return 1;
}

   
static int rl_trim (void)
{
   unsigned char *p, *pmax, *p1;
   p = This_RLI->buf + This_RLI->point;
   pmax = This_RLI->buf + This_RLI->len;
   
   if (p == pmax) 
     {
	if (p == This_RLI->buf) return 0;
	p--;
     }
   
   if ((*p != ' ') && (*p != '\t')) return 0;
   p1 = p;
   while ((p1 < pmax) && ((*p1 == ' ') || (*p1 == '\t'))) p1++;
   pmax = p1;
   p1 = This_RLI->buf;
   
   while ((p >= p1) && ((*p == ' ') || (*p == '\t'))) p--;
   if (p == pmax) return 0;
   p++;
   
   This_RLI->point = (int) (p - p1);
   return rl_deln ((int) (pmax - p));
}

static int rl_bdel (void)
{
   if (rl_left()) return rl_del();
   return 0;
}

static int rl_deleol (void)
{
   if (This_RLI->point == This_RLI->len) return 0;
   *(This_RLI->buf + This_RLI->point) = 0;
   This_RLI->len = This_RLI->point;
   return 1;
}

static int rl_delete_line (void)
{
   This_RLI->point = 0;
   *(This_RLI->buf + This_RLI->point) = 0;
   This_RLI->len = 0;
   return 1;
}

static int rl_enter (void)
{
   *(This_RLI->buf + This_RLI->len) = 0;
   SLang_Rline_Quit = 1;
   return 1;
}

static SLKeyMap_List_Type *RL_Keymap;

/* This update is designed for dumb terminals.  It assumes only that the 
 * terminal can backspace via ^H, and move cursor to start of line via ^M.
 * There is a hook so the user can provide a more sophisticated update if 
 * necessary.
 */

static void position_cursor (int col)
{
   unsigned char *p, *pmax;
   int dc;
   
   if (col == This_RLI->curs_pos) 
     {
	fflush (stdout);
	return;
     }
   
   
   if (This_RLI->tt_goto_column != NULL)
     {
	(*This_RLI->tt_goto_column)(col);
	This_RLI->curs_pos = col;
	fflush (stdout);
	return;
     }
   
   dc = This_RLI->curs_pos - col;
   if (dc < 0)
     {
	p = This_RLI->new_upd + This_RLI->curs_pos;
	pmax = This_RLI->new_upd + col;
	while (p < pmax) putc((char) *p++, stdout);
     }
   else
     {
	if (dc < col)
	  {
	     while (dc--) putc(8, stdout);
	  }
	else
	  {
	     putc('\r', stdout);
	     p = This_RLI->new_upd;
	     pmax = This_RLI->new_upd + col;
	     while (p < pmax) putc((char) *p++, stdout);
	  }
     }
   This_RLI->curs_pos = col;
   fflush (stdout);
}

static void erase_eol (SLang_RLine_Info_Type *rli)
{
   unsigned char *p, *pmax;
   
   p = rli->old_upd + rli->curs_pos;
   pmax = rli->old_upd + rli->old_upd_len;
   
   while (p++ < pmax) putc(' ', stdout);
	
   rli->curs_pos = rli->old_upd_len;
}

   
static unsigned char *spit_out(SLang_RLine_Info_Type *rli, unsigned char *p)
{
   unsigned char *pmax;
   position_cursor ((int) (p - rli->new_upd));
   pmax = rli->new_upd + rli->new_upd_len;
   while (p < pmax) putc((char) *p++, stdout);
   rli->curs_pos = rli->new_upd_len;
   return pmax;
}

static void really_update (SLang_RLine_Info_Type *rli, int new_curs_position)
{
   unsigned char *b = rli->old_upd, *p = rli->new_upd, chb, chp;
   unsigned char *pmax;
   
   if (rli->update_hook != NULL)
     {
	(*rli->update_hook)(p, rli->edit_width, new_curs_position);
     }
   else
     {
	pmax = p + rli->edit_width;
	while (p < pmax)
	  {
	     chb = *b++; chp = *p++;
	     if (chb == chp) continue;
	     
	     if (rli->old_upd_len <= rli->new_upd_len)
	       {
		  /* easy one */
		  (void) spit_out (rli, p - 1);
		  break;
	       }
	     spit_out(rli, p - 1);
	     erase_eol (rli);
	     break;
	  }
	position_cursor (new_curs_position);
     }
   
   /* update finished, so swap */
   
   rli->old_upd_len = rli->new_upd_len;
   p = rli->old_upd;
   rli->old_upd = rli->new_upd;
   rli->new_upd = p;
}

static void RLupdate (SLang_RLine_Info_Type *rli)
{
   int len, dlen, start_len = 0, prompt_len = 0, tw = 0, count;
   int want_cursor_pos;
   unsigned char *b, chb, *b_point, *p;
   int no_echo;
   
   no_echo = rli->flags & SL_RLINE_NO_ECHO;

   b_point = (unsigned char *) (rli->buf + rli->point);
   *(rli->buf + rli->len) = 0;
   
   /* expand characters for output buffer --- handle prompt first.  
    * Do two passes --- first to find out where to begin upon horiz
    * scroll and the second to actually fill the buffer. */
   len = 0;
   count = 2;			       /* once for prompt and once for buf */
   
   b = (unsigned char *) rli->prompt;
   while (count--)
     {
	if ((count == 0) && no_echo)
	  break;

	/* The prompt could be NULL */
	if (b != NULL) while ((chb = *b) != 0)
	  {
	     /* This will ensure that the screen is scrolled a third of the edit
	      * width each time */
	     if (b_point == b) break;
	     dlen = Char_Widths[chb];
	     if ((chb == '\t') && tw)
	       {
		  dlen = tw * ((len - prompt_len) / tw + 1) - (len - prompt_len);
	       }
	     len += dlen;
	     b++;
	  }
	tw = rli->tab;
	b = (unsigned char *) rli->buf;
	if (count == 1) want_cursor_pos = prompt_len = len;
     }
   
   if (len < rli->edit_width - rli->dhscroll) start_len = 0;
   else if ((rli->start_column > len)
	    || (rli->start_column + rli->edit_width <= len))
     {
	start_len = len - (rli->edit_width - rli->dhscroll);
	if (start_len < 0) start_len = 0;
     }
   else start_len = rli->start_column;
   rli->start_column = start_len;
   
   want_cursor_pos = len - start_len;

   
   /* second pass */
   p = rli->new_upd;
	
   len = 0;
   count = 2;
   b = (unsigned char *) rli->prompt;
   if (b == NULL) b = (unsigned char *) "";
   
   while ((len < start_len) && (*b))
     {
	len += Char_Widths[*b++];
     }
   
   tw = 0;
   if (*b == 0)
     {
	b = (unsigned char *) rli->buf;
	while (len < start_len)
	  {
	     len += Char_Widths[*b++];
	  }
	tw = rli->tab;
	count--;
     }
      
   len = 0;
   while (count--)
     {
	if ((count == 0) && (no_echo))
	  break;

	while ((len < rli->edit_width) && ((chb = *b++) != 0))
	  {
	     dlen = Char_Widths[chb];
	     if (dlen == 1) *p++ = chb;
	     else 
	       {
		  if ((chb == '\t') && tw)
		    {
		       dlen = tw * ((len + start_len - prompt_len) / tw + 1) - (len + start_len - prompt_len);
		       len += dlen;	       /* ok since dlen comes out 0  */
		       if (len > rli->edit_width) dlen = len - rli->edit_width;
		       while (dlen--) *p++ = ' ';
		       dlen = 0;
		    }
		  else 
		    {
		       if (dlen == 3)
			 {
			    chb &= 0x7F;
			    *p++ = '~';
			 }
		  
		       *p++ = '^';
		       if (chb == 127)  *p++ = '?';
		       else *p++ = chb + '@';
		    }
	       }
	     len += dlen;
	  }
	/* if (start_len > prompt_len) break; */
	tw = rli->tab;
	b = (unsigned char *) rli->buf;
     }
   
   rli->new_upd_len = (int) (p - rli->new_upd);
   while (p < rli->new_upd + rli->edit_width) *p++ = ' ';
   really_update (rli, want_cursor_pos);
}

void SLrline_redraw (SLang_RLine_Info_Type *rli)
{
   unsigned char *p = rli->new_upd;
   unsigned char *pmax = p + rli->edit_width;
   while (p < pmax) *p++ = ' ';
   rli->new_upd_len = rli->edit_width;
   really_update (rli, 0);
   RLupdate (rli);
}

static int rl_eof_insert (void)
{
   if (This_RLI->len == 0)
     {
	SLang_Last_Key_Char = SLang_RL_EOF_Char;
	/* rl_self_insert (); */
	return rl_enter ();
     }
   return 0;
}

int SLang_read_line (SLang_RLine_Info_Type *rli)
{
   unsigned char *p, *pmax;
   SLang_Key_Type *key;
   
   SLang_Rline_Quit = 0;
   This_RLI = rli;
   p = rli->old_upd; pmax = p + rli->edit_width;
   while (p < pmax) *p++ = ' ';
   
   /* Sanity checking */
   rli->len = strlen ((char *) rli->buf);
   if (rli->len >= rli->buf_len) 
     {
	rli->len = 0;
	*rli->buf = 0;
     }
   if (rli->point > rli->len) rli->point = rli->len;
   if (rli->point < 0) rli->point = 0;
   
   rli->curs_pos = rli->start_column = 0;
   rli->new_upd_len = rli->old_upd_len = 0;
   
   This_RLI->last_fun = NULL;
   if (rli->update_hook == NULL)
     putc ('\r', stdout);

   RLupdate (rli);
   
   while (1)
     {
	key = SLang_do_key (RL_Keymap, (int (*)(void)) rli->getkey);
	
	if ((key == NULL)
#ifdef SLKEYMAP_OBSOLETE
	    || (key->f == NULL)
#else
	    || (key->f.f == NULL)
#endif
	    )
	  {
	     rl_beep ();
	  }
	else
	  {
	     if ((SLang_Last_Key_Char == SLang_RL_EOF_Char)
		 && (*key->str == 2)
		 && (This_RLI->len == 0))
	       rl_eof_insert ();
	     else if (key->type == SLKEY_F_INTRINSIC) 
	       {
#ifdef SLKEYMAP_OBSOLETE
		  if (((int (*)(void))(key->f))())
		    RLupdate (rli);
#else
		  if ((key->f.f)()) 
		    RLupdate (rli);
#endif
	       }
	
	     if (SLang_Rline_Quit) 
	       {
		  This_RLI->buf[This_RLI->len] = 0;
		  if (SLang_Error == USER_BREAK) 
		    {
		       SLang_Error = 0;
		       return -1;
		    }
		  return This_RLI->len;
	       }
	  }
	if (key != NULL) 
	  {
#ifdef SLKEYMAP_OBSOLETE
	     This_RLI->last_fun = key->f;
#else
	     This_RLI->last_fun = key->f.f;
#endif
	  }
     }
}

static int rl_abort (void)
{
   rl_delete_line ();
   return rl_enter ();
}



/* TTY interface --- ANSI */

static void ansi_goto_column (int n)
{
   putc('\r', stdout);
   if (n) fprintf(stdout, "\033[%dC", n);
}

static void rl_select_line (SLang_Read_Line_Type *p)
{
   This_RLI->last = p;
   strcpy ((char *) This_RLI->buf, (char *) p->buf);
   This_RLI->point = This_RLI->len = strlen((char *) p->buf);
}
static int rl_next_line (void);
static int rl_prev_line (void)
{
   SLang_Read_Line_Type *prev;
   
   if (((This_RLI->last_fun != (FVOID_STAR) rl_prev_line)
	&& (This_RLI->last_fun != (FVOID_STAR) rl_next_line))
       || (This_RLI->last == NULL))
     {
	prev = This_RLI->tail;
     }
   else prev = This_RLI->last->prev;
   
   if (prev == NULL)
     {
	rl_beep ();
	return 0;
     }
   
   rl_select_line (prev);
   return 1;
}
static int rl_redraw (void)
{
   SLrline_redraw (This_RLI);
   return 1;
}

static int rl_next_line (void)
{
   SLang_Read_Line_Type *next;
   
   if (((This_RLI->last_fun != (FVOID_STAR) rl_prev_line)
	&& (This_RLI->last_fun != (FVOID_STAR) rl_next_line))
       || (This_RLI->last == NULL))
      {
	 rl_beep ();
	 return 0;
      }
   
   next = This_RLI->last->next;
   
   if (next == NULL)
     {
	This_RLI->len = This_RLI->point = 0;
	*This_RLI->buf = 0;
	This_RLI->last = NULL;
     }
   else rl_select_line (next);
   return 1;
}



static SLKeymap_Function_Type SLReadLine_Functions[] = 
{
   {"up", rl_prev_line},
   {"down", rl_next_line},
   {"bol", rl_bol},
   {"eol", rl_eol},
   {"right", rl_right},
   {"left", rl_left},
   {"self_insert", rl_self_insert},
   {"bdel", rl_bdel},
   {"del", rl_del},
   {"deleol", rl_deleol},
   {"enter", rl_enter},
   {"trim", rl_trim},
   {"quoted_insert", rl_quote_insert},
   {(char *) NULL, NULL}
};

int SLang_init_readline (SLang_RLine_Info_Type *rli)
{
   int ch;
   char simple[2];
   
   if (RL_Keymap == NULL)
     {
	simple[1] = 0;
	if (NULL == (RL_Keymap = SLang_create_keymap ("ReadLine", NULL)))
	  return -1;
	
	RL_Keymap->functions = SLReadLine_Functions;
	
	/* This breaks under some DEC ALPHA compilers (scary!) */
#ifndef __DECC
	for (ch = ' '; ch < 256; ch++)
	  {
	     simple[0] = (char) ch;
# ifdef SLKEYMAP_OBSOLETE
	     SLang_define_key1(simple, (VOID_STAR) rl_self_insert, SLKEY_F_INTRINSIC, RL_Keymap);
# else
	     SLkm_define_key (simple, (FVOID_STAR) rl_self_insert, RL_Keymap);
# endif
	  }
#else
	ch = ' ';
	while (1)
	  {
	     simple[0] = (char) ch;
# ifdef SLKEYMAP_OBSOLETE
	     SLang_define_key1(simple, (VOID_STAR) rl_self_insert, SLKEY_F_INTRINSIC, RL_Keymap);
# else
	     SLkm_define_key (simple, (FVOID_STAR) rl_self_insert, RL_Keymap);
# endif
	     ch = ch + 1;
	     if (ch == 256) break;
	  }
#endif				       /* NOT __DECC */

	simple[0] = SLang_Abort_Char;
#ifdef SLKEYMAP_OBSOLETE
	SLang_define_key1(simple, (VOID_STAR) rl_abort, SLKEY_F_INTRINSIC, RL_Keymap);
#else
	SLkm_define_key (simple, (FVOID_STAR) rl_abort, RL_Keymap);
#endif
	simple[0] = SLang_RL_EOF_Char;
#ifdef SLKEYMAP_OBSOLETE
	SLang_define_key1(simple, (VOID_STAR) rl_eof_insert, SLKEY_F_INTRINSIC, RL_Keymap);
#else
	SLkm_define_key (simple, (FVOID_STAR) rl_eof_insert, RL_Keymap);
#endif
	
#ifndef pc_system
# ifdef SLKEYMAP_OBSOLETE
	SLang_define_key1 ("^[[A", (VOID_STAR) rl_prev_line, SLKEY_F_INTRINSIC, RL_Keymap);
	SLang_define_key1 ("^[[B", (VOID_STAR) rl_next_line, SLKEY_F_INTRINSIC, RL_Keymap);
	SLang_define_key1 ("^[[C", (VOID_STAR) rl_right, SLKEY_F_INTRINSIC, RL_Keymap);
	SLang_define_key1 ("^[[D", (VOID_STAR) rl_left, SLKEY_F_INTRINSIC, RL_Keymap);
# else
	SLkm_define_key  ("^[[A", (FVOID_STAR) rl_prev_line, RL_Keymap);
	SLkm_define_key  ("^[[B", (FVOID_STAR) rl_next_line, RL_Keymap);
	SLkm_define_key  ("^[[C", (FVOID_STAR) rl_right, RL_Keymap);
	SLkm_define_key  ("^[[D", (FVOID_STAR) rl_left, RL_Keymap);
# endif
#else
# ifdef SLKEYMAP_OBSOLETE
	SLang_define_key1 ("^@H", (VOID_STAR) rl_prev_line, SLKEY_F_INTRINSIC, RL_Keymap);
	SLang_define_key1 ("^@P", (VOID_STAR) rl_next_line, SLKEY_F_INTRINSIC, RL_Keymap);
	SLang_define_key1 ("^@M", (VOID_STAR) rl_right, SLKEY_F_INTRINSIC, RL_Keymap);
	SLang_define_key1 ("^@K", (VOID_STAR) rl_left, SLKEY_F_INTRINSIC, RL_Keymap);
	SLang_define_key1 ("^@S", (VOID_STAR) rl_del, SLKEY_F_INTRINSIC, RL_Keymap);
	SLang_define_key1 ("^@O", (VOID_STAR) rl_eol, SLKEY_F_INTRINSIC, RL_Keymap);
	SLang_define_key1 ("^@G", (VOID_STAR) rl_bol, SLKEY_F_INTRINSIC, RL_Keymap);
# else
	SLkm_define_key  ("^@H", (FVOID_STAR) rl_prev_line, RL_Keymap);
	SLkm_define_key  ("^@P", (FVOID_STAR) rl_next_line, RL_Keymap);
	SLkm_define_key  ("^@M", (FVOID_STAR) rl_right, RL_Keymap);
	SLkm_define_key  ("^@K", (FVOID_STAR) rl_left, RL_Keymap);
	SLkm_define_key  ("^@S", (FVOID_STAR) rl_del, RL_Keymap);
	SLkm_define_key  ("^@O", (FVOID_STAR) rl_eol, RL_Keymap);
	SLkm_define_key  ("^@G", (FVOID_STAR) rl_bol, RL_Keymap);
# endif
#endif
#ifdef SLKEYMAP_OBSOLETE
	SLang_define_key1 ("^E", (VOID_STAR) rl_eol, SLKEY_F_INTRINSIC, RL_Keymap);
	SLang_define_key1 ("^I", (VOID_STAR) rl_self_insert, SLKEY_F_INTRINSIC, RL_Keymap);
	SLang_define_key1 ("^A", (VOID_STAR) rl_bol, SLKEY_F_INTRINSIC, RL_Keymap);
	SLang_define_key1 ("\r", (VOID_STAR) rl_enter, SLKEY_F_INTRINSIC, RL_Keymap);
	SLang_define_key1 ("\n", (VOID_STAR) rl_enter, SLKEY_F_INTRINSIC, RL_Keymap);
	SLang_define_key1 ("^K", (VOID_STAR) rl_deleol, SLKEY_F_INTRINSIC, RL_Keymap);
	SLang_define_key1 ("^L", (VOID_STAR) rl_deleol, SLKEY_F_INTRINSIC, RL_Keymap);
	SLang_define_key1 ("^V", (VOID_STAR) rl_del, SLKEY_F_INTRINSIC, RL_Keymap);
	SLang_define_key1 ("^D", (VOID_STAR) rl_del, SLKEY_F_INTRINSIC, RL_Keymap);
	SLang_define_key1 ("^F", (VOID_STAR) rl_right, SLKEY_F_INTRINSIC, RL_Keymap);
	SLang_define_key1 ("^B", (VOID_STAR) rl_left, SLKEY_F_INTRINSIC, RL_Keymap);
	SLang_define_key1 ("^?", (VOID_STAR) rl_bdel, SLKEY_F_INTRINSIC, RL_Keymap);
	SLang_define_key1 ("^H", (VOID_STAR) rl_bdel, SLKEY_F_INTRINSIC, RL_Keymap);
	SLang_define_key1 ("^P", (VOID_STAR) rl_prev_line, SLKEY_F_INTRINSIC, RL_Keymap);
	SLang_define_key1 ("^N", (VOID_STAR) rl_next_line, SLKEY_F_INTRINSIC, RL_Keymap);
	SLang_define_key1 ("^R", (VOID_STAR) rl_redraw, SLKEY_F_INTRINSIC, RL_Keymap);
	
	SLang_define_key1 ("`", (VOID_STAR) rl_quote_insert, SLKEY_F_INTRINSIC, RL_Keymap);
	SLang_define_key1 ("\033\\", (VOID_STAR) rl_trim, SLKEY_F_INTRINSIC, RL_Keymap);
#else
	SLkm_define_key  ("^C", (FVOID_STAR) rl_abort, RL_Keymap);
	SLkm_define_key  ("^E", (FVOID_STAR) rl_eol, RL_Keymap);
	SLkm_define_key  ("^G", (FVOID_STAR) rl_abort, RL_Keymap);
	SLkm_define_key  ("^I", (FVOID_STAR) rl_self_insert, RL_Keymap);
	SLkm_define_key  ("^A", (FVOID_STAR) rl_bol, RL_Keymap);
	SLkm_define_key  ("\r", (FVOID_STAR) rl_enter, RL_Keymap);
	SLkm_define_key  ("\n", (FVOID_STAR) rl_enter, RL_Keymap);
	SLkm_define_key  ("^K", (FVOID_STAR) rl_deleol, RL_Keymap);
	SLkm_define_key  ("^L", (FVOID_STAR) rl_deleol, RL_Keymap);
	SLkm_define_key  ("^V", (FVOID_STAR) rl_del, RL_Keymap);
	SLkm_define_key  ("^D", (FVOID_STAR) rl_del, RL_Keymap);
	SLkm_define_key  ("^F", (FVOID_STAR) rl_right, RL_Keymap);
	SLkm_define_key  ("^B", (FVOID_STAR) rl_left, RL_Keymap);
	SLkm_define_key  ("^?", (FVOID_STAR) rl_bdel, RL_Keymap);
	SLkm_define_key  ("^H", (FVOID_STAR) rl_bdel, RL_Keymap);
	SLkm_define_key  ("^P", (FVOID_STAR) rl_prev_line, RL_Keymap);
	SLkm_define_key  ("^N", (FVOID_STAR) rl_next_line, RL_Keymap);
	SLkm_define_key  ("^R", (FVOID_STAR) rl_redraw, RL_Keymap);
	SLkm_define_key  ("`", (FVOID_STAR) rl_quote_insert, RL_Keymap);
	SLkm_define_key  ("\033\\", (FVOID_STAR) rl_trim, RL_Keymap);
#endif	
	if (SLang_Error) return -1;
     }
   
   if (rli->prompt == NULL) rli->prompt = "";
   if (rli->keymap == NULL) rli->keymap = RL_Keymap;
   rli->old_upd = rli->upd_buf1;
   rli->new_upd = rli->upd_buf2;
   *rli->buf = 0; 
   rli->point = 0;
   
   if (rli->flags & SL_RLINE_USE_ANSI)
     {
	if (rli->tt_goto_column == NULL) rli->tt_goto_column = ansi_goto_column;
     }
   
   if (Char_Widths[0] == 2) return 0;
	
   for (ch = 0; ch < 32; ch++) Char_Widths[ch] = 2;
   for (ch = 32; ch < 256; ch++) Char_Widths[ch] = 1;
   Char_Widths[127] = 2;
#ifndef pc_system
   for (ch = 128; ch < 160; ch++) Char_Widths[ch] = 3;
#endif
   
   return 0;
}

SLang_Read_Line_Type *SLang_rline_save_line (SLang_RLine_Info_Type *rli)
{
   SLang_Read_Line_Type *rl = NULL;
   unsigned char *buf;

   if ((rli == NULL) || (rli->buf == NULL))
     return NULL;

   if (NULL == (rl = (SLang_Read_Line_Type *) SLMALLOC (sizeof (SLang_Read_Line_Type)))
       || (NULL == (buf = (unsigned char *) SLmake_string ((char *)rli->buf))))
     {
	if (rl != NULL) SLFREE (rl);
	return NULL;
     }
   rl->buf = buf;
   rl->buf_len = strlen ((char *)buf);
   rl->num = rl->misc = 0;
   rl->next = rl->prev = NULL;
      
   if (rli->tail != NULL) 
     {
	rli->tail->next = rl;
	rl->prev = rli->tail;
     }
   rli->tail = rl;
   
   return rl;
}
