[comp.sources.unix] v20i029: Command-line editor with predictions, Part01/04

rsalz@uunet.uu.net (Rich Salz) (10/18/89)

Submitted-by: Mark James <jamesm@cpsc.UCalgary.CA>
Posting-number: Volume 20, Issue 29
Archive-name: reactivekbd/part01

[  This is one of the wildest concepts I've seen; not unlike DWIM in
   the Interlisp world, I guess.  It uses pty's and BSD-style ioctl's.
   The package also has the FSF getopt(3) bundled in.  /r$  ]

The Reactive Keyboard is a general purpose command line editor with the
addition of predictive text generation.  It interfaces with a standard
shell and allows simple editing of input lines.  It will also predict new
input lines based on previous input.  Typing "make" will create the
program in the current directory.


#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 4)."
# Contents:  MANIFEST Makefile README command_line.c dt_complete.c
#   file+rk.h freq.c functions.h myabspath.c myabspath.h rk_button.c
#   rk_button.h rk_file.c
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MANIFEST'\"
else
echo shar: Extracting \"'MANIFEST'\" \(654 characters\)
sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
X   File Name		Archive #	Description
X-----------------------------------------------------------
X MANIFEST                   1	
X Makefile                   1	
X README                     1	
X command_line.c             1	
X dt_complete.c              1	
X file+rk.c                  3	
X file+rk.h                  1	
X freq.c                     1	
X functions.c                4	
X functions.h                1	
X getopt.c                   2	
X myabspath.c                1	
X myabspath.h                1	
X parse_keys.c               2	
X rk.1                       2	
X rk_button.c                1	
X rk_button.h                1	
X rk_file.c                  1	
END_OF_FILE
if test 654 -ne `wc -c <'MANIFEST'`; then
    echo shar: \"'MANIFEST'\" unpacked with wrong size!
fi
# end of 'MANIFEST'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(314+ characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
XCFLAGS = -g
X
XOBJS = file+rk.o rk_file.o rk_button.o parse_keys.o getopt.o \
X	dt_complete.o functions.o myabspath.o command_line.o
X
X.c.o:
X	cc $(CFLAGS) -c $<
X
Xall: rk rk.man freq
X
Xrk: $(OBJS)
X	cc $(CFLAGS) -o rk $(OBJS) -ltermcap
X
Xrk.man : rk.1
X	tbl rk.1|nroff -man > rk.man
X
Xfreq: freq.c
X	cc $(CFLAGS) -o freq freq.c
END_OF_FILE
echo 'shar: Size check ignored; edited by moderator for long lines.'
#if test 314 -ne `wc -c <'Makefile'`; then
#    echo shar: \"'Makefile'\" unpacked with wrong size!
#fi
# end of 'Makefile'
fi
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(454 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XThe Reactive Keyboard is a general purpose command line editor with the
Xaddition of predictive text generation.  It interfaces with a standard shell
Xand allows simple editing of input lines.  It will also predict new input
Xlines based on previous input.  Typing "make"
Xwill create the program in the current directory.
X
XPermission is granted for any individual or institution to use, copy or
Xdistribute this program so long as it is not sold for profit.
END_OF_FILE
if test 454 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'command_line.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'command_line.c'\"
else
echo shar: Extracting \"'command_line.c'\" \(5852 characters\)
sed "s/^X//" >'command_line.c' <<'END_OF_FILE'
X#define ZERO_FREQ_FILE "/.rk.zero_freq"
X#define PRIME_FILE "/.rk.log_file"
X#define KEY_FILE "/.rk.keys"
X
X#include "file+rk.h"
X#include "rk_button.h"
X#include "sys/file.h"
X#include <stdio.h>
X
Xprint_help()
X{
X	printf("RK command line arguments:\n");
X
X	printf("	-b <buffers>	The number of buffers used by rk to save previous\n");
X	printf("			 commands used by 'previous_line'. Default: 60.\n\n");
X
X	printf("	-e <length>	The maximum length of predictions at the end of the\n");
X	printf("			line. Default: 40.\n\n");
X
X
X	printf("	-f <count>	The maximum frequency count for any given context\n");
X	printf("			Default: 128\n\n");
X
X	printf("	-i <length>	The maximum length of predictions in the middle of\n");
X	printf("			the line. Default: 8.\n\n");
X
X	printf("	-k <keys file>	The file to read key bindings from.\n");
X	printf("			Default:$HOME/.rk.keys\n\n");
X
X	printf("	-n <nodes>	The amount of memory to allocate initially to speed\n");
X	printf("			up creation of nodes.  After this memory is used up,\n");
X	printf("			more will be allocated, but this will be slower.\n");
X	printf("			Default: 64*1024 nodes.\n\n");
X
X	printf("	-o <order>	This argument controls how deep a tree will be built\n");
X	printf("			by rk inorder to make predictions.  As order\n");
X	printf("			increases, the accuracy of predictions increases,\n");
X	printf("			but the speed decreases. Default: 8.\n\n");
X	printf("	-p <prime file>	The file used to prime the Reactive Keyboard.\n");
X	printf("			Default:$HOME/.rk.log_file.\n\n");
X
X
X	printf("	-s <startup>	The maximum number of characters to be read from the\n");
X	printf("			 prime file at startup. Default: 16*1024.\n\n");
X
X	printf("	-z <zero freq>	The zero frequency file name.\n");
X	printf("			Default:$HOME/.rk.zero_freq\n\n");
X
X	printf("	-A	Toggle add_space_mode\n");
X	printf("	-E	Toggle eol_only mode.\n");
X	printf("	-L	Toggle eol_longer mode.\n");
X	printf("	-N	Toggle truncate at newline mode.\n");
X	printf("	-P	Toggle predictions on/off.\n");
X	printf("	-S	Toggle show_eol_mode.\n");
X	printf("	-g	Make this not a login shell.\n");
X	printf("	-h	Print this help.\n");
X	printf("	-l	Toggle lisp mode.\n");
X	printf("	-m	Start up silently.\n");
X	printf("	-v	Print Version.\n");
X
X}
X
Xprint_version()
X{
X	char            tbuf[128];
X	printf("RK_Button Version:%s.\n", RK_VERSION);
X}
X
Xextern ED_STRUCT editor_data;
X
X
Xget_command_line_arguments(argc,argv)
Xint argc;
Xchar *argv[];
X{
X	extern int optind;
X	extern char *optarg;
X	int i;
X
X	extern num_buffers;
X	extern char *zero_freq_file;
X	static char z_freq_buf[256];
X	extern char *prime_file;
X	static char prime_buf[256];
X	extern char *key_file;
X	static char key_buf[256];
X	extern	max_len;
X	extern	max_eol;
X	extern	maxk;
X	extern	maxprime;
X	extern  max_freq;
X	extern  max_nodes;
X	extern  char silent;
X	extern  char login;
X	extern  char pred_mode,
X		     pred_on_display,
X		     lisp_mode,
X		     nl_truncate_mode,
X		     eol_only_mode,
X		     eol_longer_mode,
X	             add_space_mode,
X		     show_eol_mode;
X	
X	zero_freq_file=prime_file=key_file=NULL;
X
X	while ((i = getopt(argc, argv,"b:e:f:i:k:n:o:p:s:z:AELNPSghlmv")) 
X				!= EOF) {
X		switch( i ) {
X		case 'b': num_buffers=atoi(optarg)+1;
X			if(num_buffers<1)
X				abortit("-b:Buffers must be larger than 1.\n",-1);
X			break;
X			/* 1.. MAXINT*/
X		case 'e': max_eol=atoi(optarg);
X			if((max_eol<1)||(max_eol>132))
X				abortit("-e:End of line length must be between 1 and 132.\n",-1);
X			break;
X			/* 1..132 */
X		case 'f': max_freq=atoi(optarg);
X			if((max_freq<3)||(max_freq>255))
X				abortit("-f:Maximum Frequency must be between 3 and 255.\n",-1);
X			break;
X		case 'i': max_len=atoi(optarg);
X			if((max_len<1)||(max_len>132))
X				abortit("-i:Inline Length must be between 1 and 132.\n",-1);
X			break;
X			/* 1..132 */
X		case 'k':
X			if( key_file ) {
X				fprintf(stderr,"%s: Too many -k options\n",argv[0]);
X				abortit("",1);
X			}
X			key_file=optarg;
X			/* check for existance */
X			if(access(key_file,R_OK)){
X				perror(key_file);
X				abortit("",-1);
X			}		
X		 	break;
X		case 'n': max_nodes=atoi(optarg);
X			if(max_nodes<0)
X				abortit("-n:Number of nodes must be positive.\n",-1);
X			break;				
X		case 'o': maxk=atoi(optarg);
X			if((maxk<3)||(maxk>TOP_K)){
X				fprintf(stderr,"-o: Order must be between 3 and %d.\n",TOP_K);
X				abortit("",-1);
X			}
X			break;
X		case 'p':
X 			if( prime_file ) {
X				fprintf(stderr, "%s: Too many -p options\n",argv[0]);
X				abortit("",1);
X			}
X			prime_file=optarg;
X			/* check for existance */
X			if(access(prime_file,(R_OK|W_OK))){
X				perror(prime_file);
X				abortit("",-1);
X			}		
X			break;
X		case 's': maxprime=atoi(optarg); break;
X
X		case 'z': 
X 			if( zero_freq_file ) {
X				fprintf(stderr, "%s: Too many -z options\n",argv[0]);
X				abortit("",1);
X			}
X			zero_freq_file=optarg;
X			/* check for existance */
X			if(access(zero_freq_file,(R_OK|W_OK))){
X				perror(zero_freq_file);
X				abortit("",-1);
X			}		
X			break;
X		case 'A': add_space_mode=!add_space_mode;	break;
X		case 'E': eol_only_mode=!eol_only_mode;		break;
X		case 'L': eol_longer_mode=!eol_longer_mode;	break;
X		case 'N': nl_truncate_mode=!nl_truncate_mode;	break;
X		case 'P': pred_mode=!pred_mode;			break;
X		case 'S': show_eol_mode=!show_eol_mode;		break;
X		case 'g': login=!login; 			break;
X		case 'h': print_help();	abortit("",0);		break;
X		case 'l': lisp_mode=!lisp_mode;			break;
X		case 'm': silent=1;				break;
X		case 'v': print_version();abortit("",0);	break;
X		
X
X		default:
X			fprintf(stderr,"\r%s: Use -h for help\r\n", argv[0]);
X			abortit("",-1);
X		}
X	
X	}
X	
X	if(zero_freq_file==NULL){
X		strcpy(z_freq_buf, getenv("HOME"));
X		strcat(z_freq_buf, ZERO_FREQ_FILE );
X		zero_freq_file=z_freq_buf;
X	}
X	if(prime_file==NULL){
X		strcpy(prime_buf, getenv("HOME"));
X		strcat(prime_buf, PRIME_FILE );
X		prime_file=prime_buf;
X	}
X	if(key_file==NULL){
X		strcpy(key_buf, getenv("HOME"));
X		strcat(key_buf, KEY_FILE );
X		key_file=key_buf;
X	}
X
X}
END_OF_FILE
if test 5852 -ne `wc -c <'command_line.c'`; then
    echo shar: \"'command_line.c'\" unpacked with wrong size!
fi
# end of 'command_line.c'
fi
if test -f 'dt_complete.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'dt_complete.c'\"
else
echo shar: Extracting \"'dt_complete.c'\" \(13902 characters\)
sed "s/^X//" >'dt_complete.c' <<'END_OF_FILE'
X#include <alloca.h>	    /* JJD: some other alloc may be better to use  */
X#include <stdio.h>
X#include <sys/file.h>
X#include <sys/types.h>
X#include <sys/dir.h>
X#include <sys/stat.h>  
X#include <sys/param.h>	    /* JJD 3-89 added to get MAXPATHLEN and CANBSIZ*/
X#include "file+rk.h"
X#include "functions.h"
X
X
X#define FILECOMPLETION 3	/* change if you need to change the binding of
X				   filecompletion */
X
X/* MAX_FILENAME_LENGTH must be less than MAX_CMD_LINE_LENGTH (CANBSIZ, 256)*/
X/*									   */
X/* dir.h MAXNAMLEN is 255 (+1 for char [])	   JJD 3-89 #define	   */
X
X#define MAX_DIR_TO_SEARCH	16		/* WARNING: just a guess!  */
X#define MAX_FILES_TO_SAVE	1024		/* WARNING: just a guess!  */
X#define MAX_FILENAME_LENGTH     MAXNAMLEN 	/*          store bounds   */
X#define MAX_PATHNAME_LENGTH     MAXPATHLEN
X
Xextern num_buffers;
Xextern char *cursor_left;
Xextern char output_string[];
Xextern output_string_length;
Xextern char pred_mode,pred_on_display;
Xextern char pred_buff[];
Xextern (*keymap[128][MAXEXTENSIONS]) ();
X
Xint run_ruptime (e) ED_STRUCT *e; {
X  
X      write (1, "\015\n", 2);					/* JJD 3-89*/
X      quietly_run_program_connected_to_standard_tty ("uptime"); /* JJD 3-89*/
X      write (1, "Continue: ", 10);
X      draw_current_edit_line (e);
X      return OK;
X}
X
X/* AN IDEA: a better way would look ahead a next char, if not this, put     */
X/*	    in the read buffer and return, else stay here - write (un)getc. */
X  
Xint file_completion (e) ED_STRUCT *e; {
X      char *cwd,
X           *getcwd(),
X           *tdot,
X           *tchar,chr,
X           *f_name[MAX_FILES_TO_SAVE],		/* JJD 3-89 to ptrs, defines*/
X           tstring[MAX_CMD_LINE_LENGTH + 1],
X           de_name[MAX_FILENAME_LENGTH + 1],    /* JJD 3-89 dir entry name  */
X           full_path[MAXPATHLEN];
X
X      DIR  *opendir(),
X           *dir_pointer;
X
X      struct direct *readdir(),
X                    *d_entry;
X      int match=0,
X          length,
X          past_first=0,
X          strncmp(),
X          ful_path=0,
X          count,
X          cmatch,
X          return_this = OK;	    		 /* JJD 2-89 added */
X			/* now look for start of filename to match */
X     for (tdot=e->dot;((*tdot != ' ') && (tdot != e->current_buffer));tdot--);
X
X			/* if we aren't at the start of the whole buffer
X			   then move ahead a char (to skip the space) */
X      if (tdot != e->current_buffer) tdot++;
X                        /* and save the string to look for */
X      strcpy(tstring, tdot);
X      for (tchar=tstring;((*tchar != '\/')&&(*tchar!='\0'));tchar++);
X      if (*tchar == '\/') {
X	ful_path = 1;
X	strcpy(full_path,tstring);
X	tchar=full_path;
X	while (*tchar!='\0') tchar++;
X	while ((*tchar!='\/') && (tchar != full_path)) tchar--;
X        if (tchar != full_path) {
X	  *tchar = '\0';
X	  tchar++;strcpy(tstring,tchar);
X	}
X      }
X      if (ful_path){
X	cwd = full_path;
X      }
X      else {
X	void	(*sig)();
X	sig=signal(SIGCHLD,SIG_DFL); 
X	getcwd(full_path);cwd=full_path;	    /* get working directory */
X	signal(SIGCHLD,sig); 
X      }
X      if ((dir_pointer = opendir(cwd)) == NULL){    /* and open it to look */
X	write(1, "\07",1);
X	return OK;
X      }			/* now look for any matching filenames and
X			   increment match if we find one */
X      d_entry=readdir(dir_pointer);
X      for (; d_entry != NULL; d_entry = readdir(dir_pointer)){
X        strcpy (de_name, d_entry->d_name);
X	if (strncmp(tstring, de_name, strlen(tstring)) == 0){
X         if ((strcmp(".", de_name) != 0) &&
X             (strcmp("..", de_name) != 0)){    /* JJD 3-89 del . .. */
X	     f_name[match] = (char *) alloca (strlen(de_name) + 1);
X	     strcpy(f_name[match],de_name);
X	  if (++match >= MAX_FILES_TO_SAVE) {
X	      goto tomany;   /* JJD 3-89 forget about the rest of them */
X	  }
X	 }
X	}
X      }
Xtomany:
X      if (match == 0) {
X	write(1,"\07",1);
X	if (dir_pointer != NULL) closedir(dir_pointer); /* JJD 3-89 added if*/
X	return OK;
X      }
X			/* else we found at least 1  match */      
X      else {
X        ssort (f_name, match); /* JJD 3-89, alpha */
X	cmatch = 0;
Xagain:	output_string_length = 0;
X	if (!past_first) length=strlen(tstring);
X	else {
X	  if (cmatch == 0) length=strlen(f_name[match-1]);
X	  else length=strlen(f_name[cmatch-1]);
X	}
X	if (ful_path) length = length + strlen(full_path)+1;
X                              /* so move the cursor to the beginning
X				 of the file name */
X	for (; length; --length)
X	  tputs (cursor_left, ONE_LINE,append_to_output_string);
X                              /* set current dot to beginning of the
X				 file name and copy in the filename*/ 
X	e->dot = tdot;
X	if (ful_path){
X	  strcpy(e->dot,full_path);
X	  strcat(e->dot,"\/");
X	  strcat(e->dot,f_name[cmatch]);
X	}
X
X/* JJD: WARNING: prev and next str ops could overflow ed_buff, should test */
X
X	else strcpy(e->dot,f_name[cmatch]);
X			      /* reset dot to the end of the line */	
X        if (e->mark > e->dot) e->mark += strlen (f_name[cmatch]);/*JJD 3-89*/
X	e->dot += strlen(f_name[cmatch]);
X
X/* JJD: WARNING: prev and next dot resets could overflow ed_buff, as above */
X
X	if (ful_path) {
X          if (e->mark > e->dot) e->mark += strlen(full_path)+1;
X	  e->dot += strlen(full_path)+1;
X	}
X                              /* and concatenate onto output string the
X				 filename, write it to screen */
X	if (ful_path) {
X	  display_string_into_output_string(full_path);
X	  display_string_into_output_string("\/");
X	}
X	display_string_into_output_string (f_name[cmatch]);
X        if (cmatch == 0)length=strlen(f_name[match-1])-strlen(f_name[cmatch]);
X	else length=strlen(f_name[cmatch-1])-strlen(f_name[cmatch]);
X	for (count=0;count<length;count++){
X	  display_string_into_output_string(" ");
X	}
X	for (count=0;count<length;count++){
X	  tputs (cursor_left, ONE_LINE,append_to_output_string);
X	}
X	write (1, output_string, output_string_length);
X	if (pred_mode) {				 /* JJD 2-89 added */
X	        make_a_prediction (pred_buff);
X		if (pred_buff[0]) display_pred_buffer (e);
X	}
X	
X	READ(0,&chr,1);
X	chr &= 127;					 /* JJD 2-89 added */
X        if (pred_on_display) erase_pred_buffer (e);      /* JJD 2-89 added */
X	if (chr == FILECOMPLETION) {
X	  past_first = 1;
X	  if (cmatch < match-1) {
X	    cmatch++;
X	    goto again;
X	  }
X	  else {cmatch=0;goto again;}
X	}
X	else {
X/* JJD: it would be better to ungetc and return */
X          return_this = OK;				 /* JJD 2-89 added */
X	  e->current_input_char = chr;
X	  return_this = keymap[(int)chr][0](e); /* JJD 2-89 add return_this */
X	  if (dir_pointer != NULL) closedir(dir_pointer); /* JJD 3-89 add if*/
X	  return (return_this);		       /* JJD 2-89 add return_this */
X	}
X      }
X    }
X
X
Xint command_completion (e) ED_STRUCT *e;{
X  char *path_var,		/* points to the environment variable PATH */
X       *tdot,
X       *tchar, 
X       chr,
X	   *paths[MAX_DIR_TO_SEARCH],		/* JJD 3-89 changed to ptrs */
X           *f_name[MAX_FILES_TO_SAVE],
X           tstring[MAX_CMD_LINE_LENGTH + 1],
X           d_name[MAX_PATHNAME_LENGTH + 1],
X           de_name[MAX_FILENAME_LENGTH + 1],
X           t_name[MAX_PATHNAME_LENGTH + MAX_FILENAME_LENGTH + 1],
X       *getenv();
X  int  count,
X       num_dirs=0,		/* number of directories to look in */
X       current_search_directory,/* the current directory to look at */
X       cmatch,
X       match=0,
X       length,
X       past_first=0,
X       return_this = OK;	    		 /* JJD 2-89 added */
X
XDIR  *opendir(),
X     *dir_pointer;
X
Xstruct direct *readdir(),
X              *d_entry;
Xstruct stat   buf;				 /* JJD 3-89 added */
X
X				/* get the file name to match */  
X  for (tdot=e->dot;((*tdot != ' ') && (tdot != e->current_buffer));tdot--);
X  if (tdot != e->current_buffer) tdot++;
X  strcpy(tstring, tdot);
X
X  path_var = getenv("PATH");
X  if (path_var == NULL) {		 	 /* JJD 3-89 added test */
X    write(1,"\07",1);
X    return OK;
X  }
X  else {
X  tchar = path_var;				 /* skip the first :  */
X/* JJD: this assumes a "normal" PATH, which it is 99.99% likely to be */
X  if (path_var[0] == ':')  tchar++;		 /* JJD 3-89 added if */
X  while(*tchar != '\0'){
X    count=0;					 /* JJD 3-89 stay in bounds*/
X    while ((*tchar != ':') && (*tchar != '\0'))  d_name[count++] = *tchar++;
X    if (*tchar == ':') tchar++;  
X    d_name[count] = '\0';
X    paths[num_dirs] = (char *) alloca (strlen(d_name) + 1);
X    strcpy (paths[num_dirs], d_name);
X    if (++num_dirs >= MAX_DIR_TO_SEARCH) {
X      goto tomanydirs; /* JJD 3-89 forget the rest*/
X    }
X  }
Xtomanydirs:
X/* now have num_dirs directories to search for the command in */
X/* JJD 3-89 NOW CHECKS FOR EXECUTE PERMISSION and NOT A DIRECTORY,      */
X/* 	    THEN SORTS IN ALPHA ORDER, LEAVING IN DUPLICATED (are rare) */
X
X current_search_directory = 0;		    /* JJD 3-89 changed <= to < */
X for (;current_search_directory<num_dirs;current_search_directory++){
X    strcpy (d_name, paths[current_search_directory]); strcat (d_name, "/");
X    if ((dir_pointer = opendir(&paths[current_search_directory][0])) != NULL){
X      d_entry=readdir(dir_pointer);
X      for (;d_entry != NULL;d_entry = readdir(dir_pointer)){
X        strcpy (de_name, d_entry->d_name);
X        if (strncmp(tstring, de_name, strlen(tstring)) == 0){
X         if ((strcmp(".", de_name) != 0) &&
X             (strcmp("..", de_name) != 0)) {   /* JJD 3-89 del . .. */
X	  strcpy (t_name, d_name); strcat (t_name, de_name);
X	  if (access (t_name, X_OK) == 0) {	    /* executable */
X 	   if (stat(t_name,&buf) == 0){
X 	    if ((buf.st_mode & S_IFMT) != S_IFDIR){ /* not a dir */
X	     f_name[match] = (char *) alloca (strlen(de_name) + 1);
X	     strcpy(f_name[match],de_name);
X	     if (++match >= MAX_FILES_TO_SAVE) {
X	        goto tomanyfiles; /* JJD 3-89 above */
X	     }
X	    }
X	   }
X	  }
X	 }
X	}
X      }
X    }
Xtomanyfiles:
X    if (dir_pointer != NULL) closedir(dir_pointer);
X  }
X  if (match == 0) {
X    write(1,"\07",1);
X    return OK;
X  }
X  			/* else we found at least 1  match */      
X  else {
X    ssort (f_name, match); /* JJD 3-89, alpha */
X    cmatch = 0;
Xagain:	output_string_length = 0;
X    if (!past_first) length=strlen(tstring);
X    else {
X      if (cmatch == 0) length=strlen(f_name[match-1]);
X      else length=strlen(f_name[cmatch-1]);
X    }
X    for (; length; --length)
X      tputs (cursor_left, ONE_LINE,append_to_output_string);
X/* set current dot to beginning of the file name and copy in the filename*/ 
X    e->dot = tdot;
X    strcpy(e->dot,f_name[cmatch]);
X
X/* JJD: WARNING: prev strcpy could overflow ed_buff, should test */
X/* JJD: WARNING: next dot reset could overflow ed_buff, as above */
X			    /* reset dot to the end of the line */	
X
X    if (e->mark > e->dot) e->mark += strlen (f_name[cmatch]); /* JJD 3-89 */
X    e->dot += strlen(f_name[cmatch]);
X    display_string_into_output_string (f_name[cmatch]);
X    if (cmatch == 0) length=strlen(f_name[match-1])-strlen(f_name[cmatch]);
X    else length=strlen(f_name[cmatch-1])-strlen(f_name[cmatch]);
X    for (count=0;count<length;count++){
X	  display_string_into_output_string(" ");
X	}
X	for (count=0;count<length;count++){
X	  tputs (cursor_left, ONE_LINE,append_to_output_string);
X	}
X	write (1, output_string, output_string_length);
X	if (pred_mode) {				 /* JJD 2-89 added */
X	        make_a_prediction (pred_buff);
X		if (pred_buff[0]) display_pred_buffer (e);
X	}
X	
X	READ(0,&chr,1);
X	chr &= 127;					 /* JJD 2-89 added */
X        if (pred_on_display) erase_pred_buffer (e);      /* JJD 2-89 added */
X	if (chr == (char)28) {				 /* JJD 2-89 made ^\*/
X	  past_first = 1;
X	  if (cmatch < match-1) {
X	    cmatch++;
X	    goto again;
X	  }
X	  else {cmatch=0;goto again;}
X	}
X	else {
X/* JJD: it would be better to ungetc and return */
X          return_this = OK;				 /* JJD 2-89 added */
X	  e->current_input_char = chr;
X	  return_this = keymap[(int)chr][0](e); /* JJD 2-89 add return_this */
X	  if (dir_pointer != NULL) closedir(dir_pointer); /* JJD 3-89 add if*/
X	  return (return_this);		       /* JJD 2-89 add return_this */
X	}
X  }
X  }
X}
X
X
Xset_mark (e) ED_STRUCT *e; {
X  e->mark = e->dot;	     /* JJD 3-89 mark intialized in set_up_buffers()*/
X  e->current_ed_buff_ptr->mark = e->dot;	          /* JJD 3-89 added */
X}
X
Xshow_mark (e) ED_STRUCT *e; {
X  int num_to_go;
X  if (e->mark > e->dot){
X    e->universal_argument = num_to_go = e->mark - e->dot;
X    forward_char (e);
X    sleep(1);						/* JJD 3-89 change */
X    e->universal_argument = num_to_go;
X    backward_char (e);
X  }
X  else if (e->mark < e->dot){
X    e->universal_argument = num_to_go = e->dot - e->mark;
X    backward_char (e);
X    sleep(1);						/* JJD 3-89 change */
X    e->universal_argument = num_to_go;
X    forward_char (e);
X  }
X}
X
Xdelete_region_to_killbuffer (e) ED_STRUCT *e; {
X
X  int length;
X
X  if (e->dot > e->mark){
X    length = e->dot - e->mark;
X    strncpy(e->kill_buffer, e->mark, length);
X    e->kill_buffer[length] = '\0';
X    e->universal_argument = length;
X    backward_char(e);
X    e->universal_argument = length;
X    e->mark = e->dot;
X    return delete_char (e);
X  }
X  if (e->mark > e->dot){
X    length = e->mark - e->dot;
X    strncpy(e->kill_buffer, e->dot, length);
X    e->kill_buffer[length] = '\0';
X    e->universal_argument = length;
X    e->mark = e->dot;
X    return delete_char (e);
X  }
X  return OK;					    /* JJD 3-89 added */
X}
X
X
Xint strstr(look, lookin) char *look, *lookin;{
X    int counter = 0;
X    for (counter = 0; (counter < (strlen(lookin) - strlen(look))); counter++){
X        if (strncmp(look, &lookin[counter], strlen(look)) == 0)
X	    return(0);
X    }
X    return(1);
X}
X
X/*      
Xsend_message(message)
Xchar *message;
X{
X     ioctl (0, TIOCGETP, &new_stdin_sgttyb);
X     ioctl (0, TIOCSETP, &old_stdin_sgttyb);
X     printf ("recvd message:%s\n", message);
X     ioctl (0, TIOCSETP, &new_stdin_sgttyb);
X}
X*/
X
Xssort (v, n) char *v[]; int n; {  /* JJD: Shell Sort alla p.108 K&R C book */
X	int gap, i, j; char *temp;
X	for (gap = n/2; gap > 0; gap /= 2)
X		for (i= gap; i < n; i++)
X			for (j = i-gap; j >= 0; j -= gap) {
X			    	if (strcmp(v[j], v[j+gap]) <= 0) break;
X				temp = v[j];
X				v[j] = v[j+gap];
X				v[j+gap] = temp;
X			}
X}
END_OF_FILE
if test 13902 -ne `wc -c <'dt_complete.c'`; then
    echo shar: \"'dt_complete.c'\" unpacked with wrong size!
fi
# end of 'dt_complete.c'
fi
if test -f 'file+rk.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'file+rk.h'\"
else
echo shar: Extracting \"'file+rk.h'\" \(1071 characters\)
sed "s/^X//" >'file+rk.h' <<'END_OF_FILE'
X#include <sys/param.h>	    /* JJD 3-89 added to get MAXPATHLEN and CANBSIZ */
Xchar *strcpy(), *strcat();			    /* JJD 3-89 for lint */
Xchar *gets(), *sprintf(), *malloc();		    /* JJD 3-89 for lint */
Xchar *sprintf();				    /* JJD 3-89 for lint */
Xchar *index();
X
X#define OK                0
X#define FINISHED_EDITING -1
X#define FINISHED_BUT_DONT_ADD_CTRL_M -2
X#define HAVE_CHAR -3
X#define UNIVERSAL_ARGUMENT_MAXIMUM 256
X#define MAX_CMD_LINE_LENGTH CANBSIZ
X#define VERSION "1.0 August 21st 1989" 
X#define RK_VERSION " 1.0 August 21st 1989"	
X#define ONE_LINE (int)1			/* JJD 3-89 was int dummy for tputs */
X
X
Xstruct ed_buffs {
X    char string[MAX_CMD_LINE_LENGTH + 1];
X    char *dot;
X    char *mark;						/* JJD 3-89 added */
X    struct ed_buffs *next_ptr;
X    struct ed_buffs *prev_ptr;
X    };
X
Xtypedef struct _ed_struct {
X    char current_input_char;
X    int  universal_argument;
X    char *current_buffer;
X    char *dot;
X    char *mark;
X    char kill_buffer[MAX_CMD_LINE_LENGTH + 1];
X    struct ed_buffs *current_ed_buff_ptr;
X    } ED_STRUCT;
X
X#define MAXEXTENSIONS 12
X
END_OF_FILE
if test 1071 -ne `wc -c <'file+rk.h'`; then
    echo shar: \"'file+rk.h'\" unpacked with wrong size!
fi
# end of 'file+rk.h'
fi
if test -f 'freq.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'freq.c'\"
else
echo shar: Extracting \"'freq.c'\" \(5223 characters\)
sed "s/^X//" >'freq.c' <<'END_OF_FILE'
X/*	   Written by John Darragh, Calgary Alberta, revised 3-89.
X *
X * freq.c: tabulates ASCII character frequencies from stdin and outputs
X *         freq sorted ASCII chars on the stdout in a number of formats.
X *
X *	   intended as a utility for rk_button to create its zero_freq
X *	   startup FREQ_DATA_FILE and/or default zero_freq[] char array.
X *
X *	   this info is used by rk to predict chars it hasn't yet added
X *	   to it's model (either by file priming or user command input).
X *
X *	   it puts any unseen chars in ASCII sequence, and puts any un-
X *	   represented control codes (including DEL) at the end.
X *
X * defaults:	outputs 256 chars as 128 ASCII char/NL pairs.
X *		(the NLs are just for readabilities sake, rk ignores them.)
X *
X * options:
X *	   -c   write output as a C array for inclusion in programs.
X *         -n   don't put a NL after each of the 128 chars output.
X *		(intended for future revision to init_reactive() which
X *		 would halve the freq file size from 256 -- saves space)
X *         <filename>   read data from file other than stdin.
X */
X
X#include <stdio.h>
X
X#define TRUE    1
X#define FALSE   0
X#define MAXTABLE        128	/* the size of the ASCII character set     */
X
XFILE    * infile = stdin;	/* for <filename> arg */
Xchar	no_nls   = FALSE;	/* -n option above    */
Xchar    c_array  = FALSE;	/* -c option above    */
Xint     ch_table[MAXTABLE][2];	/* [][0] are labels, [][1] are freq counts */
X
Xmain (argc, argv)
Xint argc;
Xchar **argv;
X{
X        char chr;  register int i, j;  int gap, temp[2];
X
X        get_args (argc, argv);  /* may change infile, no_nls, c_array      */
X				/* init table labels and do the freq count */
X	for (i=0; i<MAXTABLE; i++) {
X		 ch_table[i][0] = i;	 /* the ACSII code		   */
X		 ch_table[i][1]= -(i+1); /* ensure ASCII order for 0-freqs */
X	}				    /* by intially -ve freq counts */
X        while ((chr = getc(infile)) != EOF) {
X		chr &= 0177;
X		if (ch_table[(int)chr][1] < 0)  /* seen, so fix -ve freqs */
X		    ch_table[(int)chr][1] = 0;
X		ch_table[(int)chr][1]++;
X	}
X	for (i=0; i<32; i++) {
X		if (ch_table[i][1] < 0)     /* ensure 0-freq control codes */
X		    ch_table[i][1] -= MAXTABLE;       /* end up at the end */
X	}
X	if (ch_table[MAXTABLE-1][1] < 0)     /* ensure same for DEL char   */
X		    ch_table[MAXTABLE-1][1] -= MAXTABLE;
X				/* frequency sort the thing (shell sort)   */
X	for (gap = MAXTABLE/2; gap > 0; gap /= 2)
X		for (i= gap; i < MAXTABLE; i++)
X			for (j = i-gap; j >= 0; j -= gap) {
X			    	if (ch_table[j][1] <= ch_table[j+gap][1])
X				     break;
X				temp[0] = ch_table[j][0];
X				temp[1] = ch_table[j][1];
X				ch_table[j][0] = ch_table[j+gap][0];
X				ch_table[j][1] = ch_table[j+gap][1];
X				ch_table[j+gap][0] = temp[0];
X				ch_table[j+gap][1] = temp[1];
X			}
X				/* output a compilable "C" character array */
X	if (c_array) {
Xprintf ("static char zero_freq[128] = {	     /* by a user supplied $home/file */\n");
X	    for (i=MAXTABLE-1; i>=0; i--) {
X		switch (chr = (char)(ch_table[i][0] & 127)) {
X		case '\n':  printf ("  \'\\n\',");  break;
X		case '\t':  printf ("  \'\\t\',");  break;
X		case '\b':  printf ("  \'\\b\',");  break;
X		case '\r':  printf ("  \'\\r\',");  break;
X		case '\f':  printf ("  \'\\f\',");  break;
X		case '\\':  printf ("  \'\\\\\',"); break;
X		case '\'':  printf ("  \'\\\'\',"); break;
X		case  127:  printf ("\'\\%03o\',", (int)chr); break;
X		default:    if (chr < 32) printf (" \'\\%02o\',", (int)chr);
X			    else 	  printf ("   \'%1c\',", chr); break;
X	        }
X		if (((i%8) == 0) && (i != 0)) printf ("\n");
X	    }
X	    printf ("};\n");
X				/* otherwise just put out sorted chars */
X        } else
X	    for (i=MAXTABLE-1; i>=0; i--)
X	        if (no_nls) printf ("%c",   (char)ch_table[i][0]);
X		else	    printf ("%c\n", (char)ch_table[i][0]);
X
X        abortit ("", 0);
X}
X
X
Xstatic char *options = " -n[no_nls] -c[c_array] <input file>\n";
X
Xstatic get_args (argc, argv)   /* may change infile */
Xint argc;
Xchar **argv;
X/*
X * Get any command arguments and set any appropriate
X * global flags and variables.
X */
X{
X    static char usage[256] = "usage: ";
X
X    strcat (usage, &argv[0][0]);        /* fill in name of object file */
X    strcat (usage, options);
X
X    while ((argc > 1) && (argv[1][0] == '-')) {
X        switch (argv[1][1]) {
X
X      case 'c': case 'C':               /* turn on C char array output */
X                        c_array = TRUE;
X                        break;
X
X      case 'n': case 'N':               /* turn on "no NL" output mode */
X                        no_nls = TRUE;
X                        break;
X
X      default:          abortit (usage, -1);
X
X        } /*switch*/
X        argc--; argv++;
X
X    }
X    if (argc == 2) {            /* file argument present */
X        if ((infile = fopen (&argv[1][0], "r")) == NULL) {
X            fprintf (stderr, "cannot open: %s\n", &argv[1][0]);
X            abortit (usage, -1);
X        }
X    } else if (argc != 1) abortit (usage, -1);
X}/*get_args*/
X
X
Xstatic abortit (message, status)
Xchar *message;
Xint status;
X/*
X * All program terminations are through this routine.
X * It prints an optional message, then exits with
X * the parameter status.
X */
X{
X    fprintf (stderr, "%s", message);
X    fflush (stderr);
X    exit (status);
X}/*abortit*/
END_OF_FILE
if test 5223 -ne `wc -c <'freq.c'`; then
    echo shar: \"'freq.c'\" unpacked with wrong size!
fi
# end of 'freq.c'
fi
if test -f 'functions.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'functions.h'\"
else
echo shar: Extracting \"'functions.h'\" \(1578 characters\)
sed "s/^X//" >'functions.h' <<'END_OF_FILE'
Xint	append_to_output_string();
Xint 	accept_forward_char();
Xint 	accept_forward_word();
Xint 	accept_to_end_of_line();
Xint 	backspace_char();
Xint 	backspace_word();
Xint 	backward_char();
Xint 	backward_paren();
Xint 	backward_word();
Xint 	beginning_of_line();
Xint	BOGUS();
Xint 	capitalize_word();
Xint 	clear_display();
Xint 	close_paren();
Xint 	command_completion();
Xint 	dash_to_ul_word();
Xint 	delete_char();
Xint 	delete_region_to_killbuffer();
Xint 	delete_word();
Xint 	describe_bindings();
Xint	describe_arguments();
Xint 	discard_current_edit_line();
Xint 	discard_rest_of_line();
Xint 	end_of_line();
Xint 	file_completion();
Xint 	finish_editing_line();
Xint 	forward_char();
Xint 	forward_paren();
Xint 	forward_word();
Xint 	increment_universal_argument();
Xint 	insert_interrupt_char();
Xint 	insert_quit_char();
Xint 	insert_start_char();
Xint 	insert_stop_char();
Xint 	insert_suspend_char();
Xint 	lowercase_word();
Xint 	meta_prefix();
Xint 	next_line();
Xint 	next_pred();
Xint 	open_paren();
Xint 	previous_line();
Xint 	previous_pred();
Xint 	prime_from_file();
Xint 	quote_char();
Xint 	run_mesg();
Xint 	run_pp();
Xint 	run_ruptime();
Xint 	run_talk();
Xint 	run_tty_program();
Xint 	run_write();
Xint 	self_insert();
Xint 	set_mark();
Xint 	show_free_nodes();
Xint 	show_mark();
Xint 	show_version();
Xint	toggle_add_space_mode();
Xint	toggle_show_eol_mode();
Xint 	toggle_eol_longer_mode();
Xint 	toggle_eol_only_mode();
Xint 	toggle_lisp_mode();
Xint 	toggle_nl_truncate_mode();
Xint 	toggle_pred_mode();
Xint 	twiddle_chars();
Xint 	ul_to_dash_word();
Xint 	uppercase_word();
Xint 	yank_from_kill_buffer();
END_OF_FILE
if test 1578 -ne `wc -c <'functions.h'`; then
    echo shar: \"'functions.h'\" unpacked with wrong size!
fi
# end of 'functions.h'
fi
if test -f 'myabspath.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'myabspath.c'\"
else
echo shar: Extracting \"'myabspath.c'\" \(869 characters\)
sed "s/^X//" >'myabspath.c' <<'END_OF_FILE'
X/* Mark James 89/5/24*/
X
X
X#include "myabspath.h"
X#include <pwd.h>
X#include <stdio.h>
X#include <ctype.h>
X#include <strings.h>
X
X
X/* returns 0 on success, NO_HOME if getenv("HOME") fails, NO_USER if ~user does not exist */
X
Xmyabspath(path,buff)
Xchar *path;
Xchar *buff;
X{
X	char *homedir;
X	char *getenv();
X	char username[MAX_USER_NAME];
X	int i;
X	struct passwd *pwd;
X
X	while (isspace(path[0])&&path[0])
X		path++;
X	if(path[0]=='~'){
X		path++;
X		if((path[0]=='/') || (path[0]==0)){
X			if((homedir=getenv("HOME"))==0)
X				return(NO_HOME);
X			strcpy(buff,homedir);
X			strcat(buff,path);
X			return(0);
X		}
X		else
X		{
X			for(i=0;(path[0]!='/')&&(path[0]!=0);i++,path++)
X				username[i]=path[0];
X			username[i]=0;
X			if((pwd=getpwnam(username))==0)
X				return(NO_USER);
X			strcpy(buff,pwd->pw_dir);
X			strcat(buff,path);		
X		}
X	}
X	else
X	{
X		strcpy(buff,path);
X		return(0);
X	}
X}
X
X
X
X
END_OF_FILE
if test 869 -ne `wc -c <'myabspath.c'`; then
    echo shar: \"'myabspath.c'\" unpacked with wrong size!
fi
# end of 'myabspath.c'
fi
if test -f 'myabspath.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'myabspath.h'\"
else
echo shar: Extracting \"'myabspath.h'\" \(64 characters\)
sed "s/^X//" >'myabspath.h' <<'END_OF_FILE'
X#define NO_HOME -1
X#define NO_USER -2
X
X#define MAX_USER_NAME 40
END_OF_FILE
if test 64 -ne `wc -c <'myabspath.h'`; then
    echo shar: \"'myabspath.h'\" unpacked with wrong size!
fi
# end of 'myabspath.h'
fi
if test -f 'rk_button.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rk_button.c'\"
else
echo shar: Extracting \"'rk_button.c'\" \(7389 characters\)
sed "s/^X//" >'rk_button.c' <<'END_OF_FILE'
X#include "rk_button.h"		     
X#include "file+rk.h"
X
Xextern maxk;
Xextern max_nodes;
Xextern max_freq;
Xint maxprime=16*1024;
X
X				     /** shared with rk_file/file+rk **/
Xchar   first[MAX_SET],		     /* the first letter of each pred */
X       context[MAX_CMD_LINE_LENGTH] = "\07",   /* last chars entered */
X       old_context[MAX_CMD_LINE_LENGTH] = "\07";
XBuffer Buf, CBuf;		     /* ptrs into the model k levels  */
Xchar   *prime_file;		     /* file to prime from and log to */
Xint    next_free = 0;		     /* index of next free node avail */
Xlong   psize;			     /* # chars to prime from prime_file*/
X				     /* zero freqs, maybe overwritten */
Xstatic char zero_freq[128] = {	     /* by a user supplied $home/file */
X  '\n',   ' ',   'e',   's',   't',   'r',   'a',   'l',
X   'n',   '.',   'c',   'i',   'm',   'o',   'd',   'h',
X   'p',   'u',   'f',   'b',   'w',   'g',   '-',   'y',
X   '/',   'v',   'k',   '*',   'x',   '5',   '1',   '2',
X   '4',   '>',   'q', '\07',   '3',   'z',   '0',   'j',
X   'M',   'I',   '6',  '\'',   'E',   '~',   'A',   ',',
X   'S',   'D',   'R',   '?',   'C',   '|',   'B',   'T',
X   'P',   'U',   '!',   '_',   '<',   'N',   '8',   '@',
X   '&',   '7',  '\\',   '"',   'J',   ')',   '(',   '[',
X   ']',   'F',   'L',   ':',   'O',   'K',   '9',   'H',
X   '+',   '$',   'W',   'Y',   '=',   'G',   ';',   '^',
X   '{',   'X',   'Q',   '#',   '}',   'V',   '%',   'Z',
X   '`',  '\b',  '\t', '\26', '\00', '\01', '\02', '\03',
X '\04', '\05', '\06', '\13',  '\f',  '\r', '\16', '\17',
X '\20', '\21', '\22', '\23', '\24', '\25', '\27', '\30',
X '\31', '\32', '\33', '\34', '\35', '\36', '\37','\177',};
X
Xchar *zero_freq_file;
X
Xstatic char    pred_set[MAX_SET];    /* flags chars already in first[]*/
X
Xstatic NodePtr free_nodes;	     /* now use malloc to get at init */
Xstatic NodePtr root;		     /* the root of the k model trie  */
X
XNodePtr create_node() {		     /* return ptr to a new node or abort */
X	if (next_free >= max_nodes) {
X		char *malloc(); NodePtr nptr;
X		nptr = (NodePtr) malloc((unsigned) sizeof(Node));
X		if (nptr == nil)         /* SHOULD FORGET AND CONTINUE ON */
X			abortit ("Out of memory in create_node.\n",-1);
X		next_free++;		      /* just for show_free_nodes */
X	        return(nptr);			  /* if more are needed   */
X	} else  return(&free_nodes[next_free++]); /* first nodes upto MAX */
X}
X
XNodePtr move_up(nptr, c) NodePtr nptr; char c; {
X
X	NodePtr xptr, fxptr, last_ptr, last_fptr; int state;
X
X	if (nptr == nil) xptr = nil;
X	else {
X         if (nptr->up == nil) state = START;
X         else {
X            fxptr = xptr = nptr->up;  last_fptr = last_ptr = nil;
X            state = SCANNING;
X            do {
X               if (xptr == nil) state = END;
X               else {
X                  if (fxptr->count > xptr->count) {
X		     last_fptr = last_ptr;  fxptr = xptr; }
X                  if (xptr->value == c) {
X                     state = FOUND;
X                     if (fxptr != xptr) {
X                        if (last_fptr == nil) nptr->up = xptr;
X                        else last_fptr->next = xptr;
X                        last_ptr->next = xptr->next;  xptr->next = fxptr;
X                  }  } else { last_ptr = xptr;  xptr = xptr->next; }
X            }  } while (state == SCANNING);
X         }
X         switch (state) {
X         case FOUND:
X	 	if (++(xptr->count) == max_freq) { /* Forgets on halving 1 */
X		    /*last_fptr =*/ fxptr = nptr->up;
X		    while (fxptr != nil) {		 /* JJD 9-86 */
X			fxptr->count++;
X			fxptr->count >>= 1;
X/* DOESN'T FORGET A NODES SUBTREE NODES YET SO DON'T DO IT */
X/* MAY HAcE TO INCREASE max_freq TO REDUCE HALcING & OcERHEAD */
X/* 			if (fxptr->count == 0) {
X			    last_fptr->next = fxptr->next;
Xwrite(1,"1/2 free\n",9);
X			    Free(fxptr);
X			    fxptr = last_fptr->next;
X			} else {
X			    last_fptr = fxptr; */
X			    fxptr = fxptr->next;
X			
X		    }
X		}
X		break;
X         case START: case END:
X               xptr = create_node();
X               xptr->value = c;  xptr->count = 1;
X               xptr->up = xptr->next = nil;
X	       if (state == START) nptr->up = xptr;
X	       else last_ptr->next = xptr;
X               break;
X	}}
X	return (xptr);
X}
X
Xfind_first(buf) Buffer buf; { /* find 1st char of all pred in context */
X
X	int i, order = 0; NodePtr xptr; char *p;
X
X        for (p= &pred_set[0]; p< &pred_set[MAX_SET]; p++) *p = '\0';
X	for (i=maxk-1; i>=0; i--) {      
X	    if (buf[i] != nil)
X	    if (buf[i]->up != nil) {
X		xptr = buf[i]->up;
X		while (xptr != nil) {
X		    if (!pred_set[(int)xptr->value]) {
X			pred_set[(int)xptr->value]++;
X			first[order++] = xptr->value;
X		    }  
X		    xptr = xptr->next;
X	}   }	}
X        for (p= &zero_freq[0]; p< &zero_freq[MAX_SET]; p++)
X	    if (!pred_set[(int)*p]) first[order++] = *p;
X}
X
Xchar first_pred(buf) Buffer buf; {
X    int i = maxk-1;
X    for (;;) {
X	if (buf[i] != nil)
X	    if (buf[i]->up != nil) return (buf[i]->up->value);
X	if (i == 0) return((char)1);
X	i--;
X    }
X}
X
XNodePtr scan_up(nptr,c) NodePtr nptr; char c; {
X
X	NodePtr xptr;
X	if (nptr == nil) return(nil);
X	else {
X		xptr = nptr->up;
X		for (;;) {
X			if (xptr == nil) return (nil);
X			else if (xptr->value == c) return(xptr);
X			else xptr = xptr->next;
X	}	}
X}
X
Xinit_reactive() {
X	double atof(), u;
X	register int i; FILE *from, *popen();
X	char c, *b, *rindex(), tbuf[256], home[128];
X	char cbuf[32+1], *cstart, *cend, *end; int full; long size;
X
X				/* get a bunch of nodes for starters	    */
X	free_nodes = (NodePtr) malloc((unsigned) (max_nodes * sizeof(Node)));
X        if (free_nodes == nil) {
X            sprintf (tbuf, "cannot allocate %d nodes.\n", max_nodes);
X            abortit (tbuf, -1);
X	}
X				/* set up root and pointers into model      */
X	CBuf[0] = Buf[0]	    = root = create_node();
X	root->up    = root->next = nil;
X	root->count = 1;
X	for (i=1; i<=maxk; i++) Buf[i] = nil;
X        if ((from = fopen (zero_freq_file, "r")) != NULL) {
X		i = 0;
X		while (((int)(c = getc(from))) != EOF) {
X		    zero_freq[i++] = c;
X		    if (((int)(c = getc(from))) == EOF) break; /* del NL */
X		    if (i>127) break;			 /* test if okay */
X		}
X	} /* else use built in zero_freq[] */
X				/* calc amount to prime, sys load dependent*/
X	if ((from = popen ("uptime", "r")) != NULL) {
X	    fgets (tbuf, 128, from);
X	    b = rindex (tbuf, ':');  b++;
X	    u = atof(b);
X	    pclose (from);
X	} else u = 1.0;
X	if (u > 1.0) psize = (long) ((double)((double) maxprime) / u);
X	else	     psize = (long) (maxprime);
X				/* if user has .rk.log_file, prime from it */
X        if ((from = fopen (prime_file, "r")) != NULL) {
X	    fseek (from, 0L, 2);		/* find out how long it is */
X	    size = ftell (from);
X	    if (size > psize) {			/* prime max chars at end  */
X		fseek (from, -psize, 2);           /* start after ^G mark  */
X/* on second thought, if not "logged" by rk, may be no ^Gs in the file     */
X/* 	        while ((((int)(c = getc(from))) != EOF) && (c != '\07')) ;*/
X	    } else rewind (from);
X	    cstart = cend = cbuf; end = &cbuf[maxk]; full = 0;
X	    while (((int)(c = getc(from))) != EOF) {
X		*cstart = c;
X		if (full) { ++cstart; if (cstart > end) cstart = cbuf; }
X		if (++cend > end) { cend = cbuf; full = 1; }
X		*cend = '\0';
X        	for (i=maxk; i>0; i--) Buf[i] = move_up(Buf[i-1],c);
X	    }
X	    i = 0;		/* align the context */
X	    while (cstart != cend) {
X		context[i] = old_context[i] = *cstart++; i++;
X		if (cstart > end) cstart = cbuf;
X	    }
X	    fclose (from);	
X	}
X}
X
END_OF_FILE
if test 7389 -ne `wc -c <'rk_button.c'`; then
    echo shar: \"'rk_button.c'\" unpacked with wrong size!
fi
# end of 'rk_button.c'
fi
if test -f 'rk_button.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rk_button.h'\"
else
echo shar: Extracting \"'rk_button.h'\" \(987 characters\)
sed "s/^X//" >'rk_button.h' <<'END_OF_FILE'
X/* definitions for rk_button, written by John Darragh, Calgary, revised 3-89
X */
X#include <ctype.h>
X#include <stdio.h>
X
X#define false		0
X#define true		1
X#define nil		((NodePtr)0)
X#define MAX_SET		128	     /* max # of different symbols (ASCII) */
X#define TOP_K		10
X
X#define START		0            /* values for state variables         */
X#define SCANNING	1
X#define FOUND		2
X#define END		3
X
Xtypedef struct node {                /** variable length Markov tree node **/
X        char           value;        /*  ASCII symbol value (to MAX_SET-1) */
X        char           count;        /*  frequency count (to max_freq)     */
X        struct node    *next;        /*  alternative predictions at this k */
X        struct node    *up;          /*  next k level up, eg 3 points to 4 */
X} Node;
Xtypedef Node  *NodePtr;              /** a pointer to a tree node	  **/
Xtypedef NodePtr Buffer[TOP_K+1];     /*  k ptrs into the tree k contexts   */
X
XNodePtr scan_up(), move_up();
Xchar    first_pred();
END_OF_FILE
if test 987 -ne `wc -c <'rk_button.h'`; then
    echo shar: \"'rk_button.h'\" unpacked with wrong size!
fi
# end of 'rk_button.h'
fi
if test -f 'rk_file.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rk_file.c'\"
else
echo shar: Extracting \"'rk_file.c'\" \(3279 characters\)
sed "s/^X//" >'rk_file.c' <<'END_OF_FILE'
X/* "FILE's" link to rk_button, written by John Darragh, Calgary, revised 3-89
X *
X * these are the main function used by file+rk.c to generate predictions
X */
X#include "rk_button.h"
X#include "file+rk.h"
X
Xextern int	 pred_number;		      /* Defined in file+rk.c   */
Xextern char	 nl_truncate_mode,
X		 eol_only_mode,
X		 eol_longer_mode;
X		 show_eol_mode;
Xextern ED_STRUCT editor_data;
X
Xextern char   first[MAX_SET],		      /* Defined in rk_button.c */
X              context[MAX_CMD_LINE_LENGTH],
X              old_context[MAX_CMD_LINE_LENGTH];
Xextern Buffer Buf, CBuf;
Xextern char   *prime_file;
Xextern char   pred_on_display;
Xint max_len=8;
Xint max_eol=30;
Xint maxk=8;
Xint max_freq=127;
Xint max_nodes=256*1024;  			/* 256K */
X
X
Xstatic char   temp[1024];			  /* scratch string buf */
X
X
Xmake_a_prediction (s) char *s; {    /* sets s to the current prediction */
X
X	char *a = temp; int length, i;
X	
X	if (eol_only_mode && *(editor_data.dot)) { *s = '\0'; return; }
X        strcpy (temp, context);
X	strcat (temp, editor_data.current_buffer);
X	length = strlen (temp) - strlen (editor_data.dot);
X	temp[length] = '\0';
X	if (length > maxk) a = &temp[length - maxk];
X
X	if (strcmp (old_context, a)) pred_number = 0;
X	strcpy (old_context, a);
X	
X	for (i=1; i<=maxk; i++) CBuf[i] = nil;
X	while (*a) {
X	    for (i=maxk; i>0; i--) CBuf[i] = scan_up(CBuf[i-1],*a);
X	    a++;
X	}
X	find_first(CBuf);
X        build_menu(CBuf, s);
X    }
X
Xupdate_the_model (s) char *s; { /* adds s into the model & updates log */
X
X	char *a = s, *c = s; int length, i; FILE *to;
X
X	if (strlen(s) < maxk) {
X            strcpy (temp, context);
X    	    strcat (temp, s);
X	    length = strlen (temp);
X	    if (length > maxk) a = &temp[length - maxk];
X	    else a = temp;
X	}
X	strcpy (context, a);
X	while (*c) {
X	    for (i=maxk; i>0; i--) Buf[i] = move_up(Buf[i-1],*c);
X	    c++;
X	}			/* do not save "empty" lines in the log file */
X	    			/* reopen to append log, otherwise create it */
X        if (s[0] != '\n') {	/* now log can be manipulated and still used */
X	    if ((to = fopen (prime_file, "a")) == NULL) {
X		sprintf (temp, "cannot reopen or create: %s\n", prime_file);
X		abortit (temp, -1);
X	    }
X	    fputs (s, to); fflush (to);
X	    fclose(to);
X	}
X}
X
Xbuild_menu(buf,s) Buffer buf; char *s; { /* fill out prediction in s */
X
X	int i,j,length; Buffer tbuf; char *bptr = s, c;
X
X	if (eol_longer_mode && !(*(editor_data.dot))) {
X	    length = max_eol
X	    	     - get_display_length(editor_data.current_buffer);
X	    if (length < max_len) length = max_len;
X	} else length = max_len;
X
X	c = first[pred_number];
X	for (i=0; i<=maxk; i++) tbuf[i] = buf[i];
X	for (i=1; i<=length; i++) {
X		if (show_eol_mode)
X			*bptr++ = c;
X		else if((c != '\n') || (i==1))
X			*bptr++ = c;
X		if (nl_truncate_mode && (c == '\n')) goto bp;
X		for (j=maxk; j>=1; j--) tbuf[j] = scan_up (tbuf[j-1],c);
X		c = first_pred(tbuf);
X	    }
Xbp:	*bptr = '\0';
X}
X
X
Xshutdown_() {
X    FILE *to;
X    if ((to = fopen (prime_file, "a")) != NULL) {
X        fputs ("\07", to);  fflush (to);  fclose(to);
X    }
X}
X
Xabortit (message, status)
Xchar *message;
Xint status;
X{
X    if(pred_on_display)
X	erase_pred_buffer(&editor_data);
X    shutdown_pty_and_tty();
X    shutdown_();
X    fprintf (stderr, "%s", message);
X    fflush (stdout); fflush (stderr);
X    exit (status);
X}
END_OF_FILE
if test 3279 -ne `wc -c <'rk_file.c'`; then
    echo shar: \"'rk_file.c'\" unpacked with wrong size!
fi
# end of 'rk_file.c'
fi
echo shar: End of archive 1 \(of 4\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 4 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 4 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0

-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.