git-svn-id: https://yap.svn.sf.net/svnroot/yap/trunk@2170 b08c6af1-5177-4d33-ba66-4b1c6b8b522a
		
			
				
	
	
		
			742 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			742 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*  $Id: edit.c,v 1.1 2008-03-27 00:41:33 vsc Exp $
 | 
						|
 | 
						|
    Part of SWI-Prolog
 | 
						|
 | 
						|
    Author:        Jan Wielemaker
 | 
						|
    E-mail:        jan@swi.psy.uva.nl
 | 
						|
    WWW:           http://www.swi-prolog.org
 | 
						|
    Copyright (C): 1985-2002, University of Amsterdam
 | 
						|
 | 
						|
    This library is free software; you can redistribute it and/or
 | 
						|
    modify it under the terms of the GNU Lesser General Public
 | 
						|
    License as published by the Free Software Foundation; either
 | 
						|
    version 2.1 of the License, or (at your option) any later version.
 | 
						|
 | 
						|
    This library is distributed in the hope that it will be useful,
 | 
						|
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
    Lesser General Public License for more details.
 | 
						|
 | 
						|
    You should have received a copy of the GNU Lesser General Public
 | 
						|
    License along with this library; if not, write to the Free Software
 | 
						|
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 | 
						|
*/
 | 
						|
 | 
						|
#define _MAKE_DLL 1
 | 
						|
#undef _export
 | 
						|
#include <windows.h>
 | 
						|
#include <tchar.h>
 | 
						|
#include "console.h"
 | 
						|
#include "console_i.h"
 | 
						|
#include "common.h"
 | 
						|
#include <memory.h>
 | 
						|
#include <string.h>
 | 
						|
#include <ctype.h>
 | 
						|
 | 
						|
#ifndef EOF
 | 
						|
#define EOF -1
 | 
						|
#endif
 | 
						|
 | 
						|
typedef void (*function)(Line ln, int chr);	/* edit-function */
 | 
						|
 | 
						|
static function dispatch_table[256];	/* general dispatch-table */
 | 
						|
static function dispatch_meta[256];	/* ESC-char dispatch */
 | 
						|
static RlcCompleteFunc _rlc_complete_function = rlc_complete_file_function;
 | 
						|
 | 
						|
static void	init_line_package(RlcData b);
 | 
						|
static void	bind_actions(void);
 | 
						|
 | 
						|
#ifndef min
 | 
						|
#define min(a, b) ((a) < (b) ? (a) : (b))
 | 
						|
#define max(a, b) ((a) > (b) ? (a) : (b))
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef TRUE
 | 
						|
#define TRUE 1
 | 
						|
#define FALSE 0
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef EOS
 | 
						|
#define EOS 0
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef ESC
 | 
						|
#define ESC 27
 | 
						|
#endif
 | 
						|
 | 
						|
#define COMPLETE_NEWLINE 1
 | 
						|
#define COMPLETE_EOF	 2
 | 
						|
 | 
						|
#define ctrl(c)	((c) - '@')
 | 
						|
#define META_OFFSET 128
 | 
						|
#define meta(c) ((c) + META_OFFSET)
 | 
						|
 | 
						|
		 /*******************************
 | 
						|
		 *	       BUFFER		*
 | 
						|
		 *******************************/
 | 
						|
 | 
						|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 | 
						|
make_room(Line, int room)
 | 
						|
	Make n-characters space after the point.
 | 
						|
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | 
						|
 | 
						|
static void
 | 
						|
make_room(Line ln, size_t room)
 | 
						|
{ while ( ln->size + room + 1 > ln->allocated )
 | 
						|
  { if ( !ln->data )
 | 
						|
    { ln->data = rlc_malloc(256 * sizeof(TCHAR));
 | 
						|
      ln->allocated = 256;
 | 
						|
    } else
 | 
						|
    { ln->allocated *= 2;
 | 
						|
      ln->data = rlc_realloc(ln->data, ln->allocated * sizeof(TCHAR));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  memmove(&ln->data[ln->point + room], &ln->data[ln->point],
 | 
						|
	  (ln->size - ln->point)*sizeof(TCHAR));
 | 
						|
  ln->size += room;
 | 
						|
  if ( room > 0 )
 | 
						|
    ln->change_start = min(ln->change_start, ln->point);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
set_line(Line ln, const TCHAR *s)
 | 
						|
{ size_t len = _tcslen(s);
 | 
						|
 | 
						|
  ln->size = ln->point = 0;
 | 
						|
  make_room(ln, len);
 | 
						|
  _tcsncpy(ln->data, s, len);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
terminate(Line ln)
 | 
						|
{ if ( !ln->data )
 | 
						|
  { ln->data = rlc_malloc(sizeof(TCHAR));
 | 
						|
    ln->allocated = 1;
 | 
						|
  }
 | 
						|
  ln->data[ln->size] = EOS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
delete(Line ln, size_t from, size_t len)
 | 
						|
{ if ( from < 0 || from > ln->size || len < 0 || from + len > ln->size )
 | 
						|
    return;
 | 
						|
 | 
						|
  _tcsncpy(&ln->data[from], &ln->data[from+len], ln->size - (from+len));
 | 
						|
  ln->size -= len;
 | 
						|
} 
 | 
						|
 | 
						|
 | 
						|
		 /*******************************
 | 
						|
		 *	     POSITIONING	*
 | 
						|
		 *******************************/
 | 
						|
 | 
						|
static size_t
 | 
						|
back_word(Line ln, size_t from)
 | 
						|
{ from = min(from, ln->size);
 | 
						|
  from = max(0, from);
 | 
						|
 | 
						|
  if ( ln->data )
 | 
						|
  { while(!rlc_is_word_char(ln->data[from-1]) && from > 0 )
 | 
						|
      from--;
 | 
						|
    while(rlc_is_word_char(ln->data[from-1]) && from > 0 )
 | 
						|
      from--;
 | 
						|
  }
 | 
						|
 | 
						|
  return from;
 | 
						|
}
 | 
						|
 | 
						|
static size_t
 | 
						|
forw_word(Line ln, size_t from)
 | 
						|
{ from = min(from, ln->size);
 | 
						|
  from = max(0, from);
 | 
						|
 | 
						|
  if ( ln->data )
 | 
						|
  { while(!rlc_is_word_char(ln->data[from]) && from < ln->size )
 | 
						|
      from++;
 | 
						|
    while(rlc_is_word_char(ln->data[from]) && from < ln->size )
 | 
						|
      from++;
 | 
						|
  }
 | 
						|
 | 
						|
  return from;
 | 
						|
}
 | 
						|
 | 
						|
		 /*******************************
 | 
						|
		 *       EDITING FUNCTIONS	*
 | 
						|
		 *******************************/
 | 
						|
 | 
						|
static __inline void
 | 
						|
changed(Line ln, size_t from)
 | 
						|
{ ln->change_start = min(ln->change_start, from);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
insert_self(Line ln, int chr)
 | 
						|
{ make_room(ln, 1);
 | 
						|
  ln->data[ln->point++] = chr;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
backward_delete_character(Line ln, int chr)
 | 
						|
{ if ( ln->point > 0 )
 | 
						|
  { memmove(&ln->data[ln->point-1], &ln->data[ln->point],
 | 
						|
	    (ln->size - ln->point)*sizeof(TCHAR));
 | 
						|
    ln->size--;
 | 
						|
    ln->point--;
 | 
						|
  }
 | 
						|
 | 
						|
  changed(ln, ln->point);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
delete_character(Line ln, int chr)
 | 
						|
{ if ( ln->point < ln->size )
 | 
						|
  { ln->point++;
 | 
						|
    backward_delete_character(ln, chr);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
backward_character(Line ln, int chr)
 | 
						|
{ if ( ln->point > 0 )
 | 
						|
    ln->point--;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
forward_character(Line ln, int chr)
 | 
						|
{ if ( ln->point < ln->size )
 | 
						|
    ln->point++;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
backward_word(Line ln, int chr)
 | 
						|
{ ln->point = back_word(ln, ln->point);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
forward_word(Line ln, int chr)
 | 
						|
{ ln->point = forw_word(ln, ln->point);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
backward_delete_word(Line ln, int chr)
 | 
						|
{ size_t from = back_word(ln, ln->point);
 | 
						|
  
 | 
						|
  memmove(&ln->data[from], &ln->data[ln->point],
 | 
						|
	  (ln->size - ln->point)*sizeof(TCHAR));
 | 
						|
  ln->size -= ln->point - from;
 | 
						|
  ln->point = from;
 | 
						|
  changed(ln, from);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
forward_delete_word(Line ln, int chr)
 | 
						|
{ size_t to = forw_word(ln, ln->point);
 | 
						|
  
 | 
						|
  memmove(&ln->data[ln->point], &ln->data[to], (ln->size - to)*sizeof(TCHAR));
 | 
						|
  ln->size -= to - ln->point;
 | 
						|
  changed(ln, ln->point);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
transpose_chars(Line ln, int chr)
 | 
						|
{ if ( ln->point > 0 && ln->point < ln->size )
 | 
						|
  { int c0 = ln->data[ln->point-1];
 | 
						|
    ln->data[ln->point-1] = ln->data[ln->point];
 | 
						|
    ln->data[ln->point] = c0;
 | 
						|
    changed(ln, ln->point-1);
 | 
						|
  } 
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
start_of_line(Line ln, int chr)
 | 
						|
{ ln->point = 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
end_of_line(Line ln, int chr)
 | 
						|
{ ln->point = ln->size;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
kill_line(Line ln, int chr)
 | 
						|
{ ln->size = ln->point;
 | 
						|
  changed(ln, ln->size);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
empty_line(Line ln, int chr)
 | 
						|
{ ln->size = ln->point = 0;
 | 
						|
  changed(ln, 0);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
enter(Line ln, int chr)
 | 
						|
{ ln->point = ln->size;
 | 
						|
#ifdef DOS_CRNL  
 | 
						|
  make_room(ln, 2);
 | 
						|
  ln->data[ln->point++] = '\r';
 | 
						|
  ln->data[ln->point++] = '\n';
 | 
						|
#else
 | 
						|
  make_room(ln, 1);
 | 
						|
  ln->data[ln->point++] = '\n';
 | 
						|
#endif
 | 
						|
  terminate(ln);
 | 
						|
  ln->complete = COMPLETE_NEWLINE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
eof(Line ln, int chr)
 | 
						|
{ ln->point = ln->size;
 | 
						|
  terminate(ln);
 | 
						|
  ln->complete = COMPLETE_EOF;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
delete_character_or_eof(Line ln, int chr)
 | 
						|
{ if ( ln->size == 0 )
 | 
						|
  { ln->point = ln->size;
 | 
						|
    terminate(ln);
 | 
						|
    ln->complete = COMPLETE_EOF;
 | 
						|
  } else
 | 
						|
    delete_character(ln, chr);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
undefined(Line ln, int chr)
 | 
						|
{ 
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
interrupt(Line ln, int chr)
 | 
						|
{ raise(SIGINT);
 | 
						|
}
 | 
						|
 | 
						|
		 /*******************************
 | 
						|
		 *		HISTORY		*
 | 
						|
		 *******************************/
 | 
						|
 | 
						|
static void
 | 
						|
add_history(rlc_console c, const TCHAR *data)
 | 
						|
{ const TCHAR *s = data;
 | 
						|
 | 
						|
  while(*s && *s <= ' ')
 | 
						|
    s++;
 | 
						|
 | 
						|
  if ( *s )
 | 
						|
    rlc_add_history(c, s);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
backward_history(Line ln, int chr)
 | 
						|
{ const TCHAR *h;
 | 
						|
 | 
						|
  if ( rlc_at_head_history(ln->console) && ln->size > 0 )
 | 
						|
  { terminate(ln);
 | 
						|
    add_history(ln->console, ln->data);
 | 
						|
  }
 | 
						|
 | 
						|
  if ( (h = rlc_bwd_history(ln->console)) )
 | 
						|
  { set_line(ln, h);
 | 
						|
    ln->point = ln->size;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
forward_history(Line ln, int chr)
 | 
						|
{ if ( !rlc_at_head_history(ln->console) )
 | 
						|
  { const TCHAR *h = rlc_fwd_history(ln->console);
 | 
						|
 | 
						|
    if ( h )
 | 
						|
    { set_line(ln, h);
 | 
						|
      ln->point = ln->size;
 | 
						|
    }
 | 
						|
  } else
 | 
						|
    empty_line(ln, chr);
 | 
						|
}
 | 
						|
 | 
						|
		 /*******************************
 | 
						|
		 *	      COMPLETE		*
 | 
						|
		 *******************************/
 | 
						|
 | 
						|
RlcCompleteFunc
 | 
						|
rlc_complete_hook(RlcCompleteFunc new)
 | 
						|
{ RlcCompleteFunc old = _rlc_complete_function;
 | 
						|
 | 
						|
  _rlc_complete_function = new;
 | 
						|
 | 
						|
  return old;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static int
 | 
						|
common(const TCHAR *s1, const TCHAR *s2, int insensitive)
 | 
						|
{ int n = 0;
 | 
						|
 | 
						|
  if ( !insensitive )
 | 
						|
  { while(*s1 && *s1 == *s2)
 | 
						|
    { s1++, s2++;
 | 
						|
      n++;
 | 
						|
    }
 | 
						|
    return n;
 | 
						|
  } else
 | 
						|
  { while(*s1)
 | 
						|
    { if ( _totlower(*s1) == _totlower(*s2) )
 | 
						|
      { s1++, s2++;
 | 
						|
	n++;
 | 
						|
      } else
 | 
						|
	break;
 | 
						|
    }
 | 
						|
    return n;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
complete(Line ln, int chr)
 | 
						|
{ if ( _rlc_complete_function )
 | 
						|
  { rlc_complete_data dbuf;
 | 
						|
    RlcCompleteData data = &dbuf;
 | 
						|
 | 
						|
    memset(data, 0, sizeof(dbuf));
 | 
						|
    data->line      = ln;
 | 
						|
    data->call_type = COMPLETE_INIT;
 | 
						|
 | 
						|
    if ( (*_rlc_complete_function)(data) )
 | 
						|
    { TCHAR match[COMPLETE_MAX_WORD_LEN];
 | 
						|
      int nmatches = 1;
 | 
						|
      size_t ncommon = _tcslen(data->candidate);
 | 
						|
      size_t patlen = ln->point - data->replace_from;
 | 
						|
 | 
						|
      _tcscpy(match, data->candidate);
 | 
						|
 | 
						|
      data->call_type = COMPLETE_ENUMERATE;
 | 
						|
      while( (*data->function)(data) )
 | 
						|
      { ncommon = common(match, data->candidate, data->case_insensitive);
 | 
						|
	match[ncommon] = EOS;
 | 
						|
	nmatches++;
 | 
						|
      }
 | 
						|
      data->call_type = COMPLETE_CLOSE;
 | 
						|
      (*data->function)(data);
 | 
						|
       
 | 
						|
      delete(ln, data->replace_from, patlen);
 | 
						|
      ln->point = data->replace_from;
 | 
						|
      make_room(ln, ncommon);
 | 
						|
      _tcsncpy(&ln->data[data->replace_from], match, ncommon);
 | 
						|
      ln->point += ncommon;
 | 
						|
      if ( nmatches == 1 && data->quote )
 | 
						|
	insert_self(ln, data->quote);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
#define MAX_LIST_COMPLETIONS 256
 | 
						|
 | 
						|
static void
 | 
						|
list_completions(Line ln, int chr)
 | 
						|
{ if ( _rlc_complete_function )
 | 
						|
  { rlc_complete_data dbuf;
 | 
						|
    RlcCompleteData data = &dbuf;
 | 
						|
 | 
						|
    memset(data, 0, sizeof(dbuf));
 | 
						|
    data->line      = ln;
 | 
						|
    data->call_type = COMPLETE_INIT;
 | 
						|
 | 
						|
    if ( (*_rlc_complete_function)(data) )
 | 
						|
    { TCHAR *buf[COMPLETE_MAX_MATCHES];
 | 
						|
      int n, nmatches = 0;
 | 
						|
      size_t len = _tcslen(data->candidate) + 1;
 | 
						|
      size_t longest = len;
 | 
						|
      size_t cols;
 | 
						|
 | 
						|
      buf[nmatches] = rlc_malloc(len*sizeof(TCHAR));
 | 
						|
      _tcsncpy(buf[nmatches], data->candidate, len);
 | 
						|
      nmatches++;
 | 
						|
 | 
						|
      data->call_type = COMPLETE_ENUMERATE;
 | 
						|
      while( (*data->function)(data) )
 | 
						|
      { len = _tcslen(data->candidate) + 1;
 | 
						|
	buf[nmatches] = rlc_malloc(len*sizeof(TCHAR));
 | 
						|
	_tcsncpy(buf[nmatches], data->candidate, len);
 | 
						|
	nmatches++;
 | 
						|
	longest = max(longest, len);
 | 
						|
 | 
						|
	if ( nmatches > COMPLETE_MAX_MATCHES )
 | 
						|
	{ TCHAR *msg = _T("\r\n! Too many matches\r\n");
 | 
						|
	  
 | 
						|
	  while(*msg)
 | 
						|
	    rlc_putchar(ln->console, *msg++);
 | 
						|
	  ln->reprompt = TRUE;
 | 
						|
	  data->call_type = COMPLETE_CLOSE;
 | 
						|
	  (*data->function)(data);
 | 
						|
	  return;
 | 
						|
	}
 | 
						|
      }
 | 
						|
      data->call_type = COMPLETE_CLOSE;
 | 
						|
      (*data->function)(data);
 | 
						|
 | 
						|
      cols = ScreenCols(ln->console) / longest;
 | 
						|
      rlc_putchar(ln->console, '\r');
 | 
						|
      rlc_putchar(ln->console, '\n');
 | 
						|
 | 
						|
      for(n=0; n<nmatches; )
 | 
						|
      { TCHAR *s = buf[n];
 | 
						|
	len = 0;
 | 
						|
 | 
						|
	while(*s)
 | 
						|
	{ len++;
 | 
						|
	  rlc_putchar(ln->console, *s++);
 | 
						|
	}
 | 
						|
	
 | 
						|
	rlc_free(buf[n++]);
 | 
						|
 | 
						|
	if ( n % cols == 0 )
 | 
						|
	{ rlc_putchar(ln->console, '\r');
 | 
						|
	  rlc_putchar(ln->console, '\n');
 | 
						|
	} else
 | 
						|
	{ while( len++ < longest )
 | 
						|
	  rlc_putchar(ln->console, ' ');
 | 
						|
	}
 | 
						|
      }
 | 
						|
      if ( nmatches % cols != 0 )
 | 
						|
      { rlc_putchar(ln->console, '\r');
 | 
						|
	rlc_putchar(ln->console, '\n');
 | 
						|
      }
 | 
						|
 | 
						|
      ln->reprompt = TRUE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
		 /*******************************
 | 
						|
		 *	      REPAINT		*
 | 
						|
		 *******************************/
 | 
						|
 | 
						|
static void
 | 
						|
output(rlc_console b, TCHAR *s, size_t len)
 | 
						|
{ while(len-- > 0)
 | 
						|
  { if ( *s == '\n' )
 | 
						|
      rlc_putchar(b, '\r');
 | 
						|
    rlc_putchar(b, *s++);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
update_display(Line ln)
 | 
						|
{ if ( ln->reprompt )
 | 
						|
  { const TCHAR *prompt = rlc_prompt(ln->console, NULL);
 | 
						|
    const TCHAR *s = prompt;
 | 
						|
      
 | 
						|
    rlc_putchar(ln->console, '\r');
 | 
						|
    while(*s)
 | 
						|
      rlc_putchar(ln->console, *s++);
 | 
						|
 | 
						|
    rlc_get_mark(ln->console, &ln->origin);
 | 
						|
 | 
						|
    ln->change_start = 0;
 | 
						|
    ln->reprompt = FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  rlc_goto_mark(ln->console, &ln->origin, ln->data, ln->change_start);
 | 
						|
  output(ln->console,
 | 
						|
	 &ln->data[ln->change_start], ln->size - ln->change_start);
 | 
						|
  rlc_erase_from_caret(ln->console);
 | 
						|
  rlc_goto_mark(ln->console, &ln->origin, ln->data, ln->point);
 | 
						|
  rlc_update(ln->console);
 | 
						|
 | 
						|
  ln->change_start = ln->size;
 | 
						|
}
 | 
						|
 | 
						|
		 /*******************************
 | 
						|
		 *	     TOPLEVEL		*
 | 
						|
		 *******************************/
 | 
						|
 | 
						|
TCHAR *
 | 
						|
read_line(rlc_console b)
 | 
						|
{ line ln;
 | 
						|
 | 
						|
  init_line_package(b);
 | 
						|
 | 
						|
  memset(&ln, 0, sizeof(line));
 | 
						|
  ln.console = b;
 | 
						|
  rlc_get_mark(b, &ln.origin);
 | 
						|
 | 
						|
  while(!ln.complete)
 | 
						|
  { int c;
 | 
						|
    rlc_mark m0, m1;
 | 
						|
    function func;
 | 
						|
 | 
						|
    rlc_get_mark(b, &m0);
 | 
						|
    if ( (c = getch(b)) == IMODE_SWITCH_CHAR )
 | 
						|
      return RL_CANCELED_CHARP;
 | 
						|
 | 
						|
    if ( c == EOF )
 | 
						|
    { eof(&ln, c);
 | 
						|
      update_display(&ln);
 | 
						|
      break;
 | 
						|
    } else if ( c == ESC )
 | 
						|
    { if ( (c = getch(b)) == IMODE_SWITCH_CHAR )
 | 
						|
	return RL_CANCELED_CHARP;
 | 
						|
      if ( c > 256 )
 | 
						|
	func = undefined;
 | 
						|
      else
 | 
						|
	func = dispatch_meta[c&0xff];
 | 
						|
    } else
 | 
						|
    { if ( c >= 256 )
 | 
						|
	func = insert_self;
 | 
						|
      else
 | 
						|
	func = dispatch_table[c&0xff];
 | 
						|
    }
 | 
						|
 | 
						|
    rlc_get_mark(b, &m1);
 | 
						|
 | 
						|
    (*func)(&ln, c);
 | 
						|
    if ( m0.mark_x != m1.mark_x || m0.mark_y != m1.mark_y )
 | 
						|
      ln.reprompt = TRUE;
 | 
						|
    update_display(&ln);
 | 
						|
  }
 | 
						|
  rlc_clearprompt(b);
 | 
						|
 | 
						|
  add_history(b, ln.data);
 | 
						|
 | 
						|
  return ln.data;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
		 /*******************************
 | 
						|
		 *	     DISPATCH		*
 | 
						|
		 *******************************/
 | 
						|
 | 
						|
static void
 | 
						|
init_dispatch_table()
 | 
						|
{ static int done;
 | 
						|
 | 
						|
  if ( !done )
 | 
						|
  { int n;
 | 
						|
 | 
						|
    for(n=0; n<32; n++)
 | 
						|
      dispatch_table[n] = undefined;
 | 
						|
    for(n=32; n<256; n++)
 | 
						|
      dispatch_table[n] = insert_self;
 | 
						|
    for(n=0; n<256; n++)
 | 
						|
      dispatch_meta[n] = undefined;
 | 
						|
      
 | 
						|
    bind_actions();
 | 
						|
 | 
						|
    done = TRUE;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
static void
 | 
						|
init_line_package(RlcData b)
 | 
						|
{ init_dispatch_table();
 | 
						|
  rlc_init_history(b, 50);
 | 
						|
}
 | 
						|
 | 
						|
		 /*******************************
 | 
						|
		 *	       BIND		*
 | 
						|
		 *******************************/
 | 
						|
 | 
						|
typedef struct _action
 | 
						|
{ char		*name;
 | 
						|
  function	 function;
 | 
						|
  unsigned char  keys[4];
 | 
						|
} action, *Action;
 | 
						|
 | 
						|
#define ACTION(n, f, k) { n, f, k }
 | 
						|
 | 
						|
static action actions[] = {
 | 
						|
  ACTION("insert_self",		      insert_self,		 ""),
 | 
						|
  ACTION("backward_delete_character", backward_delete_character, "\b"),
 | 
						|
  ACTION("complete",		      complete,			 "\t"),
 | 
						|
  ACTION("enter",		      enter, 			 "\r\n"),
 | 
						|
  ACTION("start_of_line",	      start_of_line,		 {ctrl('A')}),
 | 
						|
  ACTION("backward_character",	      backward_character,        {ctrl('B')}),
 | 
						|
  ACTION("interrupt",		      interrupt,		 {ctrl('C')}),
 | 
						|
  ACTION("end_of_line",		      end_of_line,		 {ctrl('E')}),
 | 
						|
  ACTION("forward_character",	      forward_character,	 {ctrl('F')}),
 | 
						|
  ACTION("transpose_chars",	      transpose_chars,		 {ctrl('T')}),
 | 
						|
  ACTION("kill_line",		      kill_line,		 {ctrl('K')}),
 | 
						|
  ACTION("backward_history",	      backward_history,		 {ctrl('P')}),
 | 
						|
  ACTION("forward_history",	      forward_history,		 {ctrl('N')}),
 | 
						|
  ACTION("empty_line",		      empty_line,		 {ctrl('U')}),
 | 
						|
  ACTION("eof",			      eof,			 {ctrl('Z')}),
 | 
						|
 | 
						|
  ACTION("delete_character_or_eof",   delete_character_or_eof,	 {ctrl('D')}),
 | 
						|
  ACTION("delete_character",	      delete_character,		 {127}),
 | 
						|
  { "forward_word",		forward_word,  {meta(ctrl('F')), meta('f')}},
 | 
						|
  { "backward_word",		backward_word, {meta(ctrl('B')), meta('b')}},
 | 
						|
  { "forward_delete_word",	forward_delete_word, {meta(127), meta('d')}},
 | 
						|
  ACTION("list_completions",	      list_completions,     {meta('?')}),
 | 
						|
  ACTION("backward_delete_word",      backward_delete_word, {meta('\b')}),
 | 
						|
 | 
						|
  ACTION(NULL,			      NULL,			 "")
 | 
						|
};
 | 
						|
 | 
						|
int
 | 
						|
rlc_bind(int chr, const char *fname)
 | 
						|
{ if ( chr >= 0 && chr <= 256 )
 | 
						|
  { Action a = actions;
 | 
						|
    
 | 
						|
    for( ; a->name; a++ )
 | 
						|
    { if ( strcmp(a->name, fname) == 0 )
 | 
						|
      { if ( chr > META_OFFSET )
 | 
						|
	  dispatch_meta[chr-META_OFFSET] = a->function;
 | 
						|
	else
 | 
						|
	  dispatch_table[chr] = a->function;
 | 
						|
 | 
						|
	return TRUE;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
bind_actions()
 | 
						|
{ Action a = actions;
 | 
						|
 | 
						|
  for( ; a->name; a++ )
 | 
						|
  { unsigned char *k = a->keys;
 | 
						|
 | 
						|
    for( ; *k; k++ )
 | 
						|
    { int chr = *k & 0xff;
 | 
						|
 | 
						|
      if ( chr > META_OFFSET )
 | 
						|
	dispatch_meta[chr-META_OFFSET] = a->function;
 | 
						|
      else
 | 
						|
	dispatch_table[chr] = a->function;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 |