diff options
author | chin <none@none> | 2007-08-17 12:01:52 -0700 |
---|---|---|
committer | chin <none@none> | 2007-08-17 12:01:52 -0700 |
commit | da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968 (patch) | |
tree | 5280d3b78e289fe9551371ab6e7f15ef9944ea14 /usr/src/lib/libshell/common/edit/emacs.c | |
parent | 073dbf9103ef2a2b05d8a16e2d26db04e0374b0e (diff) | |
download | illumos-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.c | 1444 |
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 */ |