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.