summaryrefslogtreecommitdiff
path: root/usr/src/lib/libshell/common/edit/emacs.c
diff options
context:
space:
mode:
authorchin <none@none>2007-08-17 12:01:52 -0700
committerchin <none@none>2007-08-17 12:01:52 -0700
commitda2e3ebdc1edfbc5028edf1354e7dd2fa69a7968 (patch)
tree5280d3b78e289fe9551371ab6e7f15ef9944ea14 /usr/src/lib/libshell/common/edit/emacs.c
parent073dbf9103ef2a2b05d8a16e2d26db04e0374b0e (diff)
downloadillumos-gate-da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968.tar.gz
6437624 RFE: Add ksh93 (as /usr/bin/ksh93) and libshell.so to OS/Net
6505835 AST tools and library (libpp) required for creating l10n messages for ksh93 PSARC/2006/550 Korn Shell 93 Integration PSARC/2006/587 /etc/ksh.kshrc for ksh93 PSARC/2007/035 ksh93 Amendments Contributed by Roland Mainz <roland.mainz@nrubsig.org> --HG-- rename : usr/src/lib/libcmd/common/mapfile-vers => deleted_files/usr/src/lib/libcmd/common/mapfile-vers rename : usr/src/lib/libcmd/common/placeholder.c => deleted_files/usr/src/lib/libcmd/common/placeholder.c
Diffstat (limited to 'usr/src/lib/libshell/common/edit/emacs.c')
-rw-r--r--usr/src/lib/libshell/common/edit/emacs.c1444
1 files changed, 1444 insertions, 0 deletions
diff --git a/usr/src/lib/libshell/common/edit/emacs.c b/usr/src/lib/libshell/common/edit/emacs.c
new file mode 100644
index 0000000000..0882693cc9
--- /dev/null
+++ b/usr/src/lib/libshell/common/edit/emacs.c
@@ -0,0 +1,1444 @@
+/***********************************************************************
+* *
+* This software is part of the ast package *
+* Copyright (c) 1982-2007 AT&T Knowledge Ventures *
+* and is licensed under the *
+* Common Public License, Version 1.0 *
+* by AT&T Knowledge Ventures *
+* *
+* A copy of the License is available at *
+* http://www.opensource.org/licenses/cpl1.0.txt *
+* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
+* *
+* Information and Software Systems Research *
+* AT&T Research *
+* Florham Park NJ *
+* *
+* David Korn <dgk@research.att.com> *
+* *
+***********************************************************************/
+#pragma prototyped
+/* Original version by Michael T. Veach
+ * Adapted for ksh by David Korn */
+/* EMACS_MODES: c tabstop=4
+
+One line screen editor for any program
+
+*/
+
+
+/* The following is provided by:
+ *
+ * Matthijs N. Melchior
+ * AT&T Network Systems International
+ * APT Nederland
+ * HV BZ335 x2962
+ * hvlpb!mmelchio
+ *
+ * These are now on by default
+ *
+ * ESH_NFIRST
+ * - A ^N as first history related command after the prompt will move
+ * to the next command relative to the last known history position.
+ * It will not start at the position where the last command was entered
+ * as is done by the ^P command. Every history related command will
+ * set both the current and last position. Executing a command will
+ * only set the current position.
+ *
+ * ESH_KAPPEND
+ * - Successive kill and delete commands will accumulate their data
+ * in the kill buffer, by appending or prepending as appropriate.
+ * This mode will be reset by any command not adding something to the
+ * kill buffer.
+ *
+ * ESH_BETTER
+ * - Some enhancements:
+ * - argument for a macro is passed to its replacement
+ * - ^X^H command to find out about history position (debugging)
+ * - ^X^D command to show any debugging info
+ *
+ * I do not pretend these for changes are completely independent,
+ * but you can use them to seperate features.
+ */
+
+#include <ast.h>
+#include <ctype.h>
+#include "FEATURE/cmds"
+#if KSHELL
+# include "defs.h"
+#endif /* KSHELL */
+#include "io.h"
+
+#include "history.h"
+#include "edit.h"
+#include "terminal.h"
+
+#define ESH_NFIRST
+#define ESH_KAPPEND
+#define ESH_BETTER
+
+#undef putchar
+#define putchar(ed,c) ed_putchar(ed,c)
+#define beep() ed_ringbell()
+
+
+#if SHOPT_MULTIBYTE
+# define gencpy(a,b) ed_gencpy(a,b)
+# define genncpy(a,b,n) ed_genncpy(a,b,n)
+# define genlen(str) ed_genlen(str)
+ static int print(int);
+ static int _isword(int);
+# define isword(c) _isword(out[c])
+
+#else
+# define gencpy(a,b) strcpy((char*)(a),(char*)(b))
+# define genncpy(a,b,n) strncpy((char*)(a),(char*)(b),n)
+# define genlen(str) strlen(str)
+# define print(c) isprint(c)
+# define isword(c) (isalnum(out[c]) || (out[c]=='_'))
+#endif /*SHOPT_MULTIBYTE */
+
+typedef struct _emacs_
+{
+ genchar *screen; /* pointer to window buffer */
+ genchar *cursor; /* Cursor in real screen */
+ int mark;
+ int in_mult;
+ char cr_ok;
+ char CntrlO;
+ char overflow; /* Screen overflow flag set */
+ char scvalid; /* Screen is up to date */
+ int offset; /* Screen offset */
+ enum
+ {
+ CRT=0, /* Crt terminal */
+ PAPER /* Paper terminal */
+ } terminal;
+ Histloc_t _location;
+ int prevdirection;
+ Edit_t *ed; /* pointer to edit data */
+} Emacs_t;
+
+#define editb (*ep->ed)
+#define eol editb.e_eol
+#define cur editb.e_cur
+#define hline editb.e_hline
+#define hloff editb.e_hloff
+#define hismin editb.e_hismin
+#define usrkill editb.e_kill
+#define usrlnext editb.e_lnext
+#define usreof editb.e_eof
+#define usrerase editb.e_erase
+#define crallowed editb.e_crlf
+#define Prompt editb.e_prompt
+#define plen editb.e_plen
+#define kstack editb.e_killbuf
+#define lstring editb.e_search
+#define lookahead editb.e_lookahead
+#define env editb.e_env
+#define raw editb.e_raw
+#define histlines editb.e_hismax
+#define w_size editb.e_wsize
+#define drawbuff editb.e_inbuf
+#define killing editb.e_mode
+#define location ep->_location
+
+#define LBUF 100
+#define KILLCHAR UKILL
+#define ERASECHAR UERASE
+#define EOFCHAR UEOF
+#define LNEXTCHAR ULNEXT
+#define DELETE ('a'==97?0177:7)
+
+/**********************
+A large lookahead helps when the user is inserting
+characters in the middle of the line.
+************************/
+
+
+typedef enum
+{
+ FIRST, /* First time thru for logical line, prompt on screen */
+ REFRESH, /* Redraw entire screen */
+ APPEND, /* Append char before cursor to screen */
+ UPDATE, /* Update the screen as need be */
+ FINAL /* Update screen even if pending look ahead */
+} Draw_t;
+
+static void draw(Emacs_t*,Draw_t);
+static int escape(Emacs_t*,genchar*, int);
+static void putstring(Emacs_t*,char*);
+static void search(Emacs_t*,genchar*,int);
+static void setcursor(Emacs_t*,int, int);
+static void show_info(Emacs_t*,const char*);
+static void xcommands(Emacs_t*,int);
+
+int ed_emacsread(void *context, int fd,char *buff,int scend, int reedit)
+{
+ Edit_t *ed = (Edit_t*)context;
+ register int c;
+ register int i;
+ register genchar *out;
+ register int count;
+ register Emacs_t *ep = ed->e_emacs;
+ int adjust,oadjust;
+ char backslash;
+ genchar *kptr;
+ char prompt[PRSIZE];
+ genchar Screen[MAXLINE];
+ if(!ep)
+ {
+ ep = ed->e_emacs = newof(0,Emacs_t,1,0);
+ ep->ed = ed;
+ ep->prevdirection = 1;
+ location.hist_command = -5;
+ }
+ Prompt = prompt;
+ ep->screen = Screen;
+ if(tty_raw(ERRIO,0) < 0)
+ {
+ return(reedit?reedit:ed_read(context, fd,buff,scend,0));
+ }
+ raw = 1;
+ /* This mess in case the read system call fails */
+
+ ed_setup(ep->ed,fd,reedit);
+ out = (genchar*)buff;
+#if SHOPT_MULTIBYTE
+ out = (genchar*)roundof((char*)out-(char*)0,sizeof(genchar));
+ ed_internal(buff,out);
+#endif /* SHOPT_MULTIBYTE */
+ if(!kstack)
+ {
+ kstack = (genchar*)malloc(CHARSIZE*MAXLINE);
+ kstack[0] = '\0';
+ }
+ drawbuff = out;
+#ifdef ESH_NFIRST
+ if (location.hist_command == -5) /* to be initialized */
+ {
+ kstack[0] = '\0'; /* also clear kstack... */
+ location.hist_command = hline;
+ location.hist_line = hloff;
+ }
+ if (location.hist_command <= hismin) /* don't start below minimum */
+ {
+ location.hist_command = hismin + 1;
+ location.hist_line = 0;
+ }
+ ep->in_mult = hloff; /* save pos in last command */
+#endif /* ESH_NFIRST */
+ i = sigsetjmp(env,0);
+ if (i !=0)
+ {
+ tty_cooked(ERRIO);
+ if (i == UEOF)
+ {
+ return(0); /* EOF */
+ }
+ return(-1); /* some other error */
+ }
+ out[reedit] = 0;
+ if(scend+plen > (MAXLINE-2))
+ scend = (MAXLINE-2)-plen;
+ ep->mark = 0;
+ cur = eol;
+ draw(ep,reedit?REFRESH:FIRST);
+ adjust = -1;
+ backslash = 0;
+ if (ep->CntrlO)
+ {
+#ifdef ESH_NFIRST
+ ed_ungetchar(ep->ed,cntl('N'));
+#else
+ location = hist_locate(sh.hist_ptr,location.hist_command,location.hist_line,1);
+ if (location.hist_command < histlines)
+ {
+ hline = location.hist_command;
+ hloff = location.hist_line;
+ hist_copy((char*)kstack,MAXLINE, hline,hloff);
+# if SHOPT_MULTIBYTE
+ ed_internal((char*)kstack,kstack);
+# endif /* SHOPT_MULTIBYTE */
+ ed_ungetchar(ep->ed,cntl('Y'));
+ }
+#endif /* ESH_NFIRST */
+ }
+ ep->CntrlO = 0;
+ while ((c = ed_getchar(ep->ed,0)) != (-1))
+ {
+ if (backslash)
+ {
+ backslash = 0;
+ if (c==usrerase||c==usrkill||(!print(c) &&
+ (c!='\r'&&c!='\n')))
+ {
+ /* accept a backslashed character */
+ cur--;
+ out[cur++] = c;
+ out[eol] = '\0';
+ draw(ep,APPEND);
+ continue;
+ }
+ }
+ if (c == usrkill)
+ {
+ c = KILLCHAR ;
+ }
+ else if (c == usrerase)
+ {
+ c = ERASECHAR ;
+ }
+ else if (c == usrlnext)
+ {
+ c = LNEXTCHAR ;
+ }
+ else if ((c == usreof)&&(eol == 0))
+ {
+ c = EOFCHAR;
+ }
+#ifdef ESH_KAPPEND
+ if (--killing <= 0) /* reset killing flag */
+ killing = 0;
+#endif
+ oadjust = count = adjust;
+ if(count<0)
+ count = 1;
+ adjust = -1;
+ i = cur;
+ switch(c)
+ {
+ case LNEXTCHAR:
+ c = ed_getchar(ep->ed,2);
+ goto do_default_processing;
+ case cntl('V'):
+ show_info(ep,fmtident(e_version));
+ continue;
+ case '\0':
+ ep->mark = i;
+ continue;
+ case cntl('X'):
+ xcommands(ep,count);
+ continue;
+ case EOFCHAR:
+ ed_flush(ep->ed);
+ tty_cooked(ERRIO);
+ return(0);
+#ifdef u370
+ case cntl('S') :
+ case cntl('Q') :
+ continue;
+#endif /* u370 */
+ case '\t':
+ if(cur>0 && ep->ed->sh->nextprompt)
+ {
+ if(ep->ed->e_tabcount==0)
+ {
+ ep->ed->e_tabcount=1;
+ ed_ungetchar(ep->ed,ESC);
+ goto do_escape;
+ }
+ else if(ep->ed->e_tabcount==1)
+ {
+ ed_ungetchar(ep->ed,'=');
+ goto do_escape;
+ }
+ ep->ed->e_tabcount = 0;
+ }
+ do_default_processing:
+ default:
+
+ if ((eol+1) >= (scend)) /* will not fit on line */
+ {
+ ed_ungetchar(ep->ed,c); /* save character for next line */
+ goto process;
+ }
+ for(i= ++eol; i>cur; i--)
+ out[i] = out[i-1];
+ backslash = (c == '\\');
+ out[cur++] = c;
+ draw(ep,APPEND);
+ continue;
+ case cntl('Y') :
+ {
+ c = genlen(kstack);
+ if ((c + eol) > scend)
+ {
+ beep();
+ continue;
+ }
+ ep->mark = i;
+ for(i=eol;i>=cur;i--)
+ out[c+i] = out[i];
+ kptr=kstack;
+ while (i = *kptr++)
+ out[cur++] = i;
+ draw(ep,UPDATE);
+ eol = genlen(out);
+ continue;
+ }
+ case '\n':
+ case '\r':
+ c = '\n';
+ goto process;
+
+ case DELETE: /* delete char 0x7f */
+ case '\b': /* backspace, ^h */
+ case ERASECHAR :
+ if (count > i)
+ count = i;
+#ifdef ESH_KAPPEND
+ kptr = &kstack[count]; /* move old contents here */
+ if (killing) /* prepend to killbuf */
+ {
+ c = genlen(kstack) + CHARSIZE; /* include '\0' */
+ while(c--) /* copy stuff */
+ kptr[c] = kstack[c];
+ }
+ else
+ *kptr = 0; /* this is end of data */
+ killing = 2; /* we are killing */
+ i -= count;
+ eol -= count;
+ genncpy(kstack,out+i,cur-i);
+#else
+ while ((count--)&&(i>0))
+ {
+ i--;
+ eol--;
+ }
+ genncpy(kstack,out+i,cur-i);
+ kstack[cur-i] = 0;
+#endif /* ESH_KAPPEND */
+ gencpy(out+i,out+cur);
+ ep->mark = i;
+ goto update;
+ case cntl('W') :
+#ifdef ESH_KAPPEND
+ ++killing; /* keep killing flag */
+#endif
+ if (ep->mark > eol )
+ ep->mark = eol;
+ if (ep->mark == i)
+ continue;
+ if (ep->mark > i)
+ {
+ adjust = ep->mark - i;
+ ed_ungetchar(ep->ed,cntl('D'));
+ continue;
+ }
+ adjust = i - ep->mark;
+ ed_ungetchar(ep->ed,usrerase);
+ continue;
+ case cntl('D') :
+ ep->mark = i;
+#ifdef ESH_KAPPEND
+ if (killing)
+ kptr = &kstack[genlen(kstack)]; /* append here */
+ else
+ kptr = kstack;
+ killing = 2; /* we are now killing */
+#else
+ kptr = kstack;
+#endif /* ESH_KAPPEND */
+ while ((count--)&&(eol>0)&&(i<eol))
+ {
+ *kptr++ = out[i];
+ eol--;
+ while(1)
+ {
+ if ((out[i] = out[(i+1)])==0)
+ break;
+ i++;
+ }
+ i = cur;
+ }
+ *kptr = '\0';
+ goto update;
+ case cntl('C') :
+ case cntl('F') :
+ {
+ int cntlC = (c==cntl('C'));
+ while (count-- && eol>i)
+ {
+ if (cntlC)
+ {
+ c = out[i];
+#if SHOPT_MULTIBYTE
+ if((c&~STRIP)==0 && islower(c))
+#else
+ if(islower(c))
+#endif /* SHOPT_MULTIBYTE */
+ {
+ c += 'A' - 'a';
+ out[i] = c;
+ }
+ }
+ i++;
+ }
+ goto update;
+ }
+ case cntl(']') :
+ c = ed_getchar(ep->ed,1);
+ if ((count == 0) || (count > eol))
+ {
+ beep();
+ continue;
+ }
+ if (out[i])
+ i++;
+ while (i < eol)
+ {
+ if (out[i] == c && --count==0)
+ goto update;
+ i++;
+ }
+ i = 0;
+ while (i < cur)
+ {
+ if (out[i] == c && --count==0)
+ break;
+ i++;
+ };
+
+update:
+ cur = i;
+ draw(ep,UPDATE);
+ continue;
+
+ case cntl('B') :
+ if (count > i)
+ count = i;
+ i -= count;
+ goto update;
+ case cntl('T') :
+ if ((sh_isoption(SH_EMACS))&& (eol!=i))
+ i++;
+ if (i >= 2)
+ {
+ c = out[i - 1];
+ out[i-1] = out[i-2];
+ out[i-2] = c;
+ }
+ else
+ {
+ if(sh_isoption(SH_EMACS))
+ i--;
+ beep();
+ continue;
+ }
+ goto update;
+ case cntl('A') :
+ i = 0;
+ goto update;
+ case cntl('E') :
+ i = eol;
+ goto update;
+ case cntl('U') :
+ adjust = 4*count;
+ continue;
+ case KILLCHAR :
+ cur = 0;
+ oadjust = -1;
+ case cntl('K') :
+ if(oadjust >= 0)
+ {
+#ifdef ESH_KAPPEND
+ killing = 2; /* set killing signal */
+#endif
+ ep->mark = count;
+ ed_ungetchar(ep->ed,cntl('W'));
+ continue;
+ }
+ i = cur;
+ eol = i;
+ ep->mark = i;
+#ifdef ESH_KAPPEND
+ if (killing) /* append to kill buffer */
+ gencpy(&kstack[genlen(kstack)], &out[i]);
+ else
+ gencpy(kstack,&out[i]);
+ killing = 2; /* set killing signal */
+#else
+ gencpy(kstack,&out[i]);
+#endif /* ESH_KAPPEND */
+ out[i] = 0;
+ draw(ep,UPDATE);
+ if (c == KILLCHAR)
+ {
+ if (ep->terminal == PAPER)
+ {
+ putchar(ep->ed,'\n');
+ putstring(ep,Prompt);
+ }
+ c = ed_getchar(ep->ed,0);
+ if (c != usrkill)
+ {
+ ed_ungetchar(ep->ed,c);
+ continue;
+ }
+ if (ep->terminal == PAPER)
+ ep->terminal = CRT;
+ else
+ {
+ ep->terminal = PAPER;
+ putchar(ep->ed,'\n');
+ putstring(ep,Prompt);
+ }
+ }
+ continue;
+ case cntl('L'):
+ ed_crlf(ep->ed);
+ draw(ep,REFRESH);
+ continue;
+ case cntl('[') :
+ do_escape:
+ adjust = escape(ep,out,oadjust);
+ continue;
+ case cntl('R') :
+ search(ep,out,count);
+ goto drawline;
+ case cntl('P') :
+ if (count <= hloff)
+ hloff -= count;
+ else
+ {
+ hline -= count - hloff;
+ hloff = 0;
+ }
+#ifdef ESH_NFIRST
+ if (hline <= hismin)
+#else
+ if (hline < hismin)
+#endif /* ESH_NFIRST */
+ {
+ hline = hismin+1;
+ beep();
+#ifndef ESH_NFIRST
+ continue;
+#endif
+ }
+ goto common;
+
+ case cntl('O') :
+ location.hist_command = hline;
+ location.hist_line = hloff;
+ ep->CntrlO = 1;
+ c = '\n';
+ goto process;
+ case cntl('N') :
+#ifdef ESH_NFIRST
+ hline = location.hist_command; /* start at saved position */
+ hloff = location.hist_line;
+#endif /* ESH_NFIRST */
+ location = hist_locate(sh.hist_ptr,hline,hloff,count);
+ if (location.hist_command > histlines)
+ {
+ beep();
+#ifdef ESH_NFIRST
+ location.hist_command = histlines;
+ location.hist_line = ep->in_mult;
+#else
+ continue;
+#endif /* ESH_NFIRST */
+ }
+ hline = location.hist_command;
+ hloff = location.hist_line;
+ common:
+#ifdef ESH_NFIRST
+ location.hist_command = hline; /* save current position */
+ location.hist_line = hloff;
+#endif
+ hist_copy((char*)out,MAXLINE, hline,hloff);
+#if SHOPT_MULTIBYTE
+ ed_internal((char*)(out),out);
+#endif /* SHOPT_MULTIBYTE */
+ drawline:
+ eol = genlen(out);
+ cur = eol;
+ draw(ep,UPDATE);
+ continue;
+ }
+
+ }
+
+process:
+
+ if (c == (-1))
+ {
+ lookahead = 0;
+ beep();
+ *out = '\0';
+ }
+ draw(ep,FINAL);
+ tty_cooked(ERRIO);
+ if(ed->e_nlist)
+ {
+ ed->e_nlist = 0;
+ stakset(ed->e_stkptr,ed->e_stkoff);
+ }
+ if(c == '\n')
+ {
+ out[eol++] = '\n';
+ out[eol] = '\0';
+ ed_crlf(ep->ed);
+ }
+#if SHOPT_MULTIBYTE
+ ed_external(out,buff);
+#endif /* SHOPT_MULTIBYTE */
+ i = strlen(buff);
+ if (i)
+ return(i);
+ return(-1);
+}
+
+static void show_info(Emacs_t *ep,const char *str)
+{
+ register genchar *out = drawbuff;
+ register int c;
+ genchar string[LBUF];
+ int sav_cur = cur;
+ /* save current line */
+ genncpy(string,out,sizeof(string)/sizeof(*string));
+ *out = 0;
+ cur = 0;
+#if SHOPT_MULTIBYTE
+ ed_internal(str,out);
+#else
+ gencpy(out,str);
+#endif /* SHOPT_MULTIBYTE */
+ draw(ep,UPDATE);
+ c = ed_getchar(ep->ed,0);
+ if(c!=' ')
+ ed_ungetchar(ep->ed,c);
+ /* restore line */
+ cur = sav_cur;
+ genncpy(out,string,sizeof(string)/sizeof(*string));
+ draw(ep,UPDATE);
+}
+
+static void putstring(Emacs_t* ep,register char *sp)
+{
+ register int c;
+ while (c= *sp++)
+ putchar(ep->ed,c);
+}
+
+
+static int escape(register Emacs_t* ep,register genchar *out,int count)
+{
+ register int i,value;
+ int digit,ch;
+ digit = 0;
+ value = 0;
+ while ((i=ed_getchar(ep->ed,0)),isdigit(i))
+ {
+ value *= 10;
+ value += (i - '0');
+ digit = 1;
+ }
+ if (digit)
+ {
+ ed_ungetchar(ep->ed,i) ;
+#ifdef ESH_KAPPEND
+ ++killing; /* don't modify killing signal */
+#endif
+ return(value);
+ }
+ value = count;
+ if(value<0)
+ value = 1;
+ switch(ch=i)
+ {
+ case cntl('V'):
+ show_info(ep,fmtident(e_version));
+ return(-1);
+ case ' ':
+ ep->mark = cur;
+ return(-1);
+
+#ifdef ESH_KAPPEND
+ case '+': /* M-+ = append next kill */
+ killing = 2;
+ return -1; /* no argument for next command */
+#endif
+
+ case 'p': /* M-p == ^W^Y (copy stack == kill & yank) */
+ ed_ungetchar(ep->ed,cntl('Y'));
+ ed_ungetchar(ep->ed,cntl('W'));
+#ifdef ESH_KAPPEND
+ killing = 0; /* start fresh */
+#endif
+ return(-1);
+
+ case 'l': /* M-l == lower-case */
+ case 'd':
+ case 'c':
+ case 'f':
+ {
+ i = cur;
+ while(value-- && i<eol)
+ {
+ while ((out[i])&&(!isword(i)))
+ i++;
+ while ((out[i])&&(isword(i)))
+ i++;
+ }
+ if(ch=='l')
+ {
+ value = i-cur;
+ while (value-- > 0)
+ {
+ i = out[cur];
+#if SHOPT_MULTIBYTE
+ if((i&~STRIP)==0 && isupper(i))
+#else
+ if(isupper(i))
+#endif /* SHOPT_MULTIBYTE */
+ {
+ i += 'a' - 'A';
+ out[cur] = i;
+ }
+ cur++;
+ }
+ draw(ep,UPDATE);
+ return(-1);
+ }
+
+ else if(ch=='f')
+ goto update;
+ else if(ch=='c')
+ {
+ ed_ungetchar(ep->ed,cntl('C'));
+ return(i-cur);
+ }
+ else
+ {
+ if (i-cur)
+ {
+ ed_ungetchar(ep->ed,cntl('D'));
+#ifdef ESH_KAPPEND
+ ++killing; /* keep killing signal */
+#endif
+ return(i-cur);
+ }
+ beep();
+ return(-1);
+ }
+ }
+
+
+ case 'b':
+ case DELETE :
+ case '\b':
+ case 'h':
+ {
+ i = cur;
+ while(value-- && i>0)
+ {
+ i--;
+ while ((i>0)&&(!isword(i)))
+ i--;
+ while ((i>0)&&(isword(i-1)))
+ i--;
+ }
+ if(ch=='b')
+ goto update;
+ else
+ {
+ ed_ungetchar(ep->ed,usrerase);
+#ifdef ESH_KAPPEND
+ ++killing;
+#endif
+ return(cur-i);
+ }
+ }
+
+ case '>':
+ ed_ungetchar(ep->ed,cntl('N'));
+#ifdef ESH_NFIRST
+ if (ep->in_mult)
+ {
+ location.hist_command = histlines;
+ location.hist_line = ep->in_mult - 1;
+ }
+ else
+ {
+ location.hist_command = histlines - 1;
+ location.hist_line = 0;
+ }
+#else
+ hline = histlines-1;
+ hloff = 0;
+#endif /* ESH_NFIRST */
+ return(0);
+
+ case '<':
+ ed_ungetchar(ep->ed,cntl('P'));
+ hloff = 0;
+#ifdef ESH_NFIRST
+ hline = hismin + 1;
+ return 0;
+#else
+ return(hline-hismin);
+#endif /* ESH_NFIRST */
+
+
+ case '#':
+ ed_ungetchar(ep->ed,'\n');
+ ed_ungetchar(ep->ed,(out[0]=='#')?cntl('D'):'#');
+ ed_ungetchar(ep->ed,cntl('A'));
+ return(-1);
+ case '_' :
+ case '.' :
+ {
+ genchar name[MAXLINE];
+ char buf[MAXLINE];
+ char *ptr;
+ ptr = hist_word(buf,MAXLINE,(count?count:-1));
+#if !KSHELL
+ if(ptr==0)
+ {
+ beep();
+ break;
+ }
+#endif /* KSHELL */
+ if ((eol - cur) >= sizeof(name))
+ {
+ beep();
+ return(-1);
+ }
+ ep->mark = cur;
+ gencpy(name,&out[cur]);
+ while(*ptr)
+ {
+ out[cur++] = *ptr++;
+ eol++;
+ }
+ gencpy(&out[cur],name);
+ draw(ep,UPDATE);
+ return(-1);
+ }
+#if KSHELL
+
+ /* file name expansion */
+ case cntl('[') : /* filename completion */
+ i = '\\';
+ case '*': /* filename expansion */
+ case '=': /* escape = - list all matching file names */
+ ep->mark = cur;
+ if(ed_expand(ep->ed,(char*)out,&cur,&eol,i,count) < 0)
+ {
+ if(ep->ed->e_tabcount==1)
+ {
+ ep->ed->e_tabcount=2;
+ ed_ungetchar(ep->ed,cntl('\t'));
+ return(-1);
+ }
+ beep();
+ }
+ else if(i=='=')
+ {
+ draw(ep,REFRESH);
+ if(count>0)
+ ep->ed->e_tabcount=0;
+ else
+ {
+ i=ed_getchar(ep->ed,0);
+ ed_ungetchar(ep->ed,i);
+ if(isdigit(i))
+ ed_ungetchar(ep->ed,ESC);
+ }
+ }
+ else
+ {
+ if(i=='\\' && cur>ep->mark && (out[cur-1]=='/' || out[cur-1]==' '))
+ ep->ed->e_tabcount=0;
+ draw(ep,UPDATE);
+ }
+ return(-1);
+
+ /* search back for character */
+ case cntl(']'): /* feature not in book */
+ {
+ int c = ed_getchar(ep->ed,1);
+ if ((value == 0) || (value > eol))
+ {
+ beep();
+ return(-1);
+ }
+ i = cur;
+ if (i > 0)
+ i--;
+ while (i >= 0)
+ {
+ if (out[i] == c && --value==0)
+ goto update;
+ i--;
+ }
+ i = eol;
+ while (i > cur)
+ {
+ if (out[i] == c && --value==0)
+ break;
+ i--;
+ };
+
+ }
+ update:
+ cur = i;
+ draw(ep,UPDATE);
+ return(-1);
+
+#ifdef _cmd_tput
+ case cntl('L'): /* clear screen */
+ sh_trap("tput clear", 0);
+ draw(ep,REFRESH);
+ return(-1);
+#endif
+ case '[': /* feature not in book */
+ switch(i=ed_getchar(ep->ed,1))
+ {
+ case 'A':
+ ed_ungetchar(ep->ed,cntl('P'));
+ return(-1);
+ case 'B':
+ ed_ungetchar(ep->ed,cntl('N'));
+ return(-1);
+ case 'C':
+ ed_ungetchar(ep->ed,cntl('F'));
+ return(-1);
+ case 'D':
+ ed_ungetchar(ep->ed,cntl('B'));
+ return(-1);
+ case 'H':
+ ed_ungetchar(ep->ed,cntl('A'));
+ return(-1);
+ case 'Y':
+ ed_ungetchar(ep->ed,cntl('E'));
+ return(-1);
+ default:
+ ed_ungetchar(ep->ed,i);
+ }
+ i = '_';
+
+ default:
+ /* look for user defined macro definitions */
+ if(ed_macro(ep->ed,i))
+# ifdef ESH_BETTER
+ return(count); /* pass argument to macro */
+# else
+ return(-1);
+# endif /* ESH_BETTER */
+#else
+ update:
+ cur = i;
+ draw(ep,UPDATE);
+ return(-1);
+
+ default:
+#endif /* KSHELL */
+ beep();
+ return(-1);
+ }
+}
+
+
+/*
+ * This routine process all commands starting with ^X
+ */
+
+static void xcommands(register Emacs_t *ep,int count)
+{
+ register int i = ed_getchar(ep->ed,0);
+ NOT_USED(count);
+ switch(i)
+ {
+ case cntl('X'): /* exchange dot and mark */
+ if (ep->mark > eol)
+ ep->mark = eol;
+ i = ep->mark;
+ ep->mark = cur;
+ cur = i;
+ draw(ep,UPDATE);
+ return;
+
+#if KSHELL
+# ifdef ESH_BETTER
+ case cntl('E'): /* invoke emacs on current command */
+ if(ed_fulledit(ep->ed)==-1)
+ beep();
+ else
+ {
+#if SHOPT_MULTIBYTE
+ ed_internal((char*)drawbuff,drawbuff);
+#endif /* SHOPT_MULTIBYTE */
+ ed_ungetchar(ep->ed,'\n');
+ }
+ return;
+
+# define itos(i) fmtbase((long)(i),0,0)/* want signed conversion */
+
+ case cntl('H'): /* ^X^H show history info */
+ {
+ char hbuf[MAXLINE];
+
+ strcpy(hbuf, "Current command ");
+ strcat(hbuf, itos(hline));
+ if (hloff)
+ {
+ strcat(hbuf, " (line ");
+ strcat(hbuf, itos(hloff+1));
+ strcat(hbuf, ")");
+ }
+ if ((hline != location.hist_command) ||
+ (hloff != location.hist_line))
+ {
+ strcat(hbuf, "; Previous command ");
+ strcat(hbuf, itos(location.hist_command));
+ if (location.hist_line)
+ {
+ strcat(hbuf, " (line ");
+ strcat(hbuf, itos(location.hist_line+1));
+ strcat(hbuf, ")");
+ }
+ }
+ show_info(ep,hbuf);
+ return;
+ }
+# if 0 /* debugging, modify as required */
+ case cntl('D'): /* ^X^D show debugging info */
+ {
+ char debugbuf[MAXLINE];
+
+ strcpy(debugbuf, "count=");
+ strcat(debugbuf, itos(count));
+ strcat(debugbuf, " eol=");
+ strcat(debugbuf, itos(eol));
+ strcat(debugbuf, " cur=");
+ strcat(debugbuf, itos(cur));
+ strcat(debugbuf, " crallowed=");
+ strcat(debugbuf, itos(crallowed));
+ strcat(debugbuf, " plen=");
+ strcat(debugbuf, itos(plen));
+ strcat(debugbuf, " w_size=");
+ strcat(debugbuf, itos(w_size));
+
+ show_info(ep,debugbuf);
+ return;
+ }
+# endif /* debugging code */
+# endif /* ESH_BETTER */
+#endif /* KSHELL */
+
+ default:
+ beep();
+ return;
+ }
+}
+
+static void search(Emacs_t* ep,genchar *out,int direction)
+{
+#ifndef ESH_NFIRST
+ Histloc_t location;
+#endif
+ register int i,sl;
+ genchar str_buff[LBUF];
+ register genchar *string = drawbuff;
+ /* save current line */
+ int sav_cur = cur;
+ genncpy(str_buff,string,sizeof(str_buff)/sizeof(*str_buff));
+ string[0] = '^';
+ string[1] = 'R';
+ string[2] = '\0';
+ sl = 2;
+ cur = sl;
+ draw(ep,UPDATE);
+ while ((i = ed_getchar(ep->ed,1))&&(i != '\r')&&(i != '\n'))
+ {
+ if (i==usrerase || i==DELETE || i=='\b' || i==ERASECHAR)
+ {
+ if (sl > 2)
+ {
+ string[--sl] = '\0';
+ cur = sl;
+ draw(ep,UPDATE);
+ }
+ else
+ beep();
+ continue;
+ }
+ if (i==usrkill)
+ {
+ beep();
+ goto restore;
+ }
+ if (i == '\\')
+ {
+ string[sl++] = '\\';
+ string[sl] = '\0';
+ cur = sl;
+ draw(ep,APPEND);
+ i = ed_getchar(ep->ed,1);
+ string[--sl] = '\0';
+ }
+ string[sl++] = i;
+ string[sl] = '\0';
+ cur = sl;
+ draw(ep,APPEND);
+ }
+ i = genlen(string);
+
+ if (direction < 1)
+ {
+ ep->prevdirection = -ep->prevdirection;
+ direction = 1;
+ }
+ else
+ direction = -1;
+ if (i != 2)
+ {
+#if SHOPT_MULTIBYTE
+ ed_external(string,(char*)string);
+#endif /* SHOPT_MULTIBYTE */
+ strncpy(lstring,((char*)string)+2,SEARCHSIZE);
+ ep->prevdirection = direction;
+ }
+ else
+ direction = ep->prevdirection ;
+ location = hist_find(sh.hist_ptr,(char*)lstring,hline,1,direction);
+ i = location.hist_command;
+ if(i>0)
+ {
+ hline = i;
+#ifdef ESH_NFIRST
+ hloff = location.hist_line = 0; /* display first line of multi line command */
+#else
+ hloff = location.hist_line;
+#endif /* ESH_NFIRST */
+ hist_copy((char*)out,MAXLINE, hline,hloff);
+#if SHOPT_MULTIBYTE
+ ed_internal((char*)out,out);
+#endif /* SHOPT_MULTIBYTE */
+ return;
+ }
+ if (i < 0)
+ {
+ beep();
+#ifdef ESH_NFIRST
+ location.hist_command = hline;
+ location.hist_line = hloff;
+#else
+ hloff = 0;
+ hline = histlines;
+#endif /* ESH_NFIRST */
+ }
+restore:
+ genncpy(string,str_buff,sizeof(str_buff)/sizeof(*str_buff));
+ cur = sav_cur;
+ return;
+}
+
+
+/* Adjust screen to agree with inputs: logical line and cursor */
+/* If 'first' assume screen is blank */
+/* Prompt is always kept on the screen */
+
+static void draw(register Emacs_t *ep,Draw_t option)
+{
+#define NORMAL ' '
+#define LOWER '<'
+#define BOTH '*'
+#define UPPER '>'
+
+ register genchar *sptr; /* Pointer within screen */
+ genchar nscreen[2*MAXLINE]; /* New entire screen */
+ genchar *ncursor; /* New cursor */
+ register genchar *nptr; /* Pointer to New screen */
+ char longline; /* Line overflow */
+ genchar *logcursor;
+ genchar *nscend; /* end of logical screen */
+ register int i;
+
+ nptr = nscreen;
+ sptr = drawbuff;
+ logcursor = sptr + cur;
+ longline = NORMAL;
+
+ if (option == FIRST || option == REFRESH)
+ {
+ ep->overflow = NORMAL;
+ ep->cursor = ep->screen;
+ ep->offset = 0;
+ ep->cr_ok = crallowed;
+ if (option == FIRST)
+ {
+ ep->scvalid = 1;
+ return;
+ }
+ *ep->cursor = '\0';
+ putstring(ep,Prompt); /* start with prompt */
+ }
+
+ /*********************
+ Do not update screen if pending characters
+ **********************/
+
+ if ((lookahead)&&(option != FINAL))
+ {
+
+ ep->scvalid = 0; /* Screen is out of date, APPEND will not work */
+
+ return;
+ }
+
+ /***************************************
+ If in append mode, cursor at end of line, screen up to date,
+ the previous character was a 'normal' character,
+ and the window has room for another character.
+ Then output the character and adjust the screen only.
+ *****************************************/
+
+
+ i = *(logcursor-1); /* last character inserted */
+
+ if ((option == APPEND)&&(ep->scvalid)&&(*logcursor == '\0')&&
+ print(i)&&((ep->cursor-ep->screen)<(w_size-1)))
+ {
+ putchar(ep->ed,i);
+ *ep->cursor++ = i;
+ *ep->cursor = '\0';
+ return;
+ }
+
+ /* copy the line */
+ ncursor = nptr + ed_virt_to_phys(ep->ed,sptr,nptr,cur,0,0);
+ nptr += genlen(nptr);
+ sptr += genlen(sptr);
+ nscend = nptr - 1;
+ if(sptr == logcursor)
+ ncursor = nptr;
+
+ /*********************
+ Does ncursor appear on the screen?
+ If not, adjust the screen offset so it does.
+ **********************/
+
+ i = ncursor - nscreen;
+
+ if ((ep->offset && i<=ep->offset)||(i >= (ep->offset+w_size)))
+ {
+ /* Center the cursor on the screen */
+ ep->offset = i - (w_size>>1);
+ if (--ep->offset < 0)
+ ep->offset = 0;
+ }
+
+ /*********************
+ Is the range of screen[0] thru screen[w_size] up-to-date
+ with nscreen[offset] thru nscreen[offset+w_size] ?
+ If not, update as need be.
+ ***********************/
+
+ nptr = &nscreen[ep->offset];
+ sptr = ep->screen;
+
+ i = w_size;
+
+ while (i-- > 0)
+ {
+
+ if (*nptr == '\0')
+ {
+ *(nptr + 1) = '\0';
+ *nptr = ' ';
+ }
+ if (*sptr == '\0')
+ {
+ *(sptr + 1) = '\0';
+ *sptr = ' ';
+ }
+ if (*nptr == *sptr)
+ {
+ nptr++;
+ sptr++;
+ continue;
+ }
+ setcursor(ep,sptr-ep->screen,*nptr);
+ *sptr++ = *nptr++;
+#if SHOPT_MULTIBYTE
+ while(*nptr==MARKER)
+ {
+ if(*sptr=='\0')
+ *(sptr + 1) = '\0';
+ *sptr++ = *nptr++;
+ i--;
+ ep->cursor++;
+ }
+#endif /* SHOPT_MULTIBYTE */
+ }
+
+ /******************
+
+ Screen overflow checks
+
+ ********************/
+
+ if (nscend >= &nscreen[ep->offset+w_size])
+ {
+ if (ep->offset > 0)
+ longline = BOTH;
+ else
+ longline = UPPER;
+ }
+ else
+ {
+ if (ep->offset > 0)
+ longline = LOWER;
+ }
+
+ /* Update screen overflow indicator if need be */
+
+ if (longline != ep->overflow)
+ {
+ setcursor(ep,w_size,longline);
+ ep->overflow = longline;
+ }
+ i = (ncursor-nscreen) - ep->offset;
+ setcursor(ep,i,0);
+ if(option==FINAL && ep->ed->e_multiline)
+ setcursor(ep,nscend-nscreen,0);
+ ep->scvalid = 1;
+ return;
+}
+
+/*
+ * put the cursor to the <newp> position within screen buffer
+ * if <c> is non-zero then output this character
+ * cursor is set to reflect the change
+ */
+
+static void setcursor(register Emacs_t *ep,register int newp,int c)
+{
+ register int oldp = ep->cursor - ep->screen;
+ newp = ed_setcursor(ep->ed, ep->screen, oldp, newp, 0);
+ if(c)
+ {
+ putchar(ep->ed,c);
+ newp++;
+ }
+ ep->cursor = ep->screen+newp;
+ return;
+}
+
+#if SHOPT_MULTIBYTE
+static int print(register int c)
+{
+ return((c&~STRIP)==0 && isprint(c));
+}
+
+static int _isword(register int c)
+{
+ return((c&~STRIP) || isalnum(c) || c=='_');
+}
+#endif /* SHOPT_MULTIBYTE */