| 
									
										
										
										
											2014-02-26 22:10:17 +00:00
										 |  |  | /*  $Id$
 | 
					
						
							| 
									
										
										
										
											2008-03-27 00:41:33 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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 | 
					
						
							| 
									
										
										
										
											2014-02-26 22:10:17 +00:00
										 |  |  |     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA | 
					
						
							| 
									
										
										
										
											2008-03-27 00:41:33 +00:00
										 |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <windows.h>
 | 
					
						
							|  |  |  | #include <tchar.h>
 | 
					
						
							| 
									
										
										
										
											2014-02-26 22:10:17 +00:00
										 |  |  | #define _MAKE_DLL 1
 | 
					
						
							|  |  |  | #undef _export
 | 
					
						
							| 
									
										
										
										
											2008-03-27 00:41:33 +00:00
										 |  |  | #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; | 
					
						
							| 
									
										
										
										
											2014-02-26 22:10:17 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2008-03-27 00:41:33 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		 /*******************************
 | 
					
						
							|  |  |  | 		 *	     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); | 
					
						
							| 
									
										
										
										
											2014-02-26 22:10:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-27 00:41:33 +00:00
										 |  |  |   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); | 
					
						
							| 
									
										
										
										
											2014-02-26 22:10:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-27 00:41:33 +00:00
										 |  |  |   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); | 
					
						
							| 
									
										
										
										
											2014-02-26 22:10:17 +00:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2008-03-27 00:41:33 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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; | 
					
						
							| 
									
										
										
										
											2014-02-26 22:10:17 +00:00
										 |  |  | #ifdef DOS_CRNL
 | 
					
						
							| 
									
										
										
										
											2008-03-27 00:41:33 +00:00
										 |  |  |   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) | 
					
						
							| 
									
										
										
										
											2014-02-26 22:10:17 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2008-03-27 00:41:33 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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); | 
					
						
							| 
									
										
										
										
											2014-02-26 22:10:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-27 00:41:33 +00:00
										 |  |  |       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"); | 
					
						
							| 
									
										
										
										
											2014-02-26 22:10:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-27 00:41:33 +00:00
										 |  |  | 	  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++); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-02-26 22:10:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-27 00:41:33 +00:00
										 |  |  | 	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; | 
					
						
							| 
									
										
										
										
											2014-02-26 22:10:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-27 00:41:33 +00:00
										 |  |  |     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 | 
					
						
							| 
									
										
										
										
											2014-03-06 02:03:10 +00:00
										 |  |  | init_dispatch_table(void) | 
					
						
							| 
									
										
										
										
											2008-03-27 00:41:33 +00:00
										 |  |  | { 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; | 
					
						
							| 
									
										
										
										
											2014-02-26 22:10:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-27 00:41:33 +00:00
										 |  |  |     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; | 
					
						
							| 
									
										
										
										
											2014-02-26 22:10:17 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-03-27 00:41:33 +00:00
										 |  |  |     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; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |