/* * put <string> of length <nbyte> onto lookahead stack * if <type> is non-zero, the negation of the character is put * onto the stack so that it can be checked for KEYTRAP * putstack() returns 1 except when in the middle of a multi-byte char */ static int putstack(Edit_t *ep,char string[], register int nbyte, int type) { register int c; #if SHOPT_MULTIBYTE char *endp, *p=string; int size, offset = ep->e_lookahead + nbyte; *(endp = &p[nbyte]) = 0; endp = &p[nbyte]; do { c = (int)((*p) & STRIP); if(c< 0x80 && c!='<') { if (type) c = -c; # ifndef CBREAK if(c == '\0') { /*** user break key ***/ ep->e_lookahead = 0; # if KSHELL sh_fault(SIGINT); siglongjmp(ep->e_env, UINTR); # endif /* KSHELL */ } # endif /* CBREAK */ } else { again: if((c=mbchar(p)) >=0) { p--; /* incremented below */ if(type) c = -c; } #ifdef EILSEQ else if(errno == EILSEQ) errno = 0; #endif else if((endp-p) < mbmax()) { if ((c=ed_read(ep,ep->e_fd,endp, 1,0)) == 1) { *++endp = 0; goto again; } return(c); } else { ed_ringbell(); c = -(int)((*p) & STRIP); offset += mbmax()-1; } } ep->e_lbuf[--offset] = c; p++; } while (p < endp); /* shift lookahead buffer if necessary */ if(offset -= ep->e_lookahead) { for(size=offset;size < nbyte;size++) ep->e_lbuf[ep->e_lookahead+size-offset] = ep->e_lbuf[ep->e_lookahead+size]; } ep->e_lookahead += nbyte-offset; #else while (nbyte > 0) { c = string[--nbyte] & STRIP; ep->e_lbuf[ep->e_lookahead++] = (type?-c:c); # ifndef CBREAK if( c == '\0' ) { /*** user break key ***/ ep->e_lookahead = 0; # if KSHELL sh_fault(SIGINT); siglongjmp(ep->e_env, UINTR); # endif /* KSHELL */ } # endif /* CBREAK */ } #endif /* SHOPT_MULTIBYTE */ return(1); }
/* * routine to perform read from terminal for vi and emacs mode * <mode> can be one of the following: * -2 vi insert mode - key binding is in effect * -1 vi control mode - key binding is in effect * 0 normal command mode - key binding is in effect * 1 edit keys not mapped * 2 Next key is literal */ int ed_getchar(register Edit_t *ep,int mode) { register int n, c; char readin[LOOKAHEAD+1]; if(!ep->e_lookahead) { ed_flush(ep); ep->e_inmacro = 0; /* The while is necessary for reads of partial multbyte chars */ *ep->e_vi_insert = (mode==-2); if((n=ed_read(ep,ep->e_fd,readin,-LOOKAHEAD,0)) > 0) n = putstack(ep,readin,n,1); *ep->e_vi_insert = 0; } if(ep->e_lookahead) { /* check for possible key mapping */ if((c = ep->e_lbuf[--ep->e_lookahead]) < 0) { if(mode<=0 && -c == ep->e_intr) { sh_fault(SIGINT); siglongjmp(ep->e_env, UINTR); } if(mode<=0 && ep->sh->st.trap[SH_KEYTRAP]) { ep->e_keytrap = 1; n=1; if((readin[0]= -c) == ESC) { while(1) { if(!ep->e_lookahead) { if((c=sfpkrd(ep->e_fd,readin+n,1,'\r',(mode?400L:-1L),0))>0) putstack(ep,readin+n,c,1); } if(!ep->e_lookahead) break; if((c=ep->e_lbuf[--ep->e_lookahead])>=0) { ep->e_lookahead++; break; } c = -c; readin[n++] = c; if(c>='0' && c<='9' && n>2) continue; if(n>2 || (c!= '[' && c!= 'O')) break; } } if(n=keytrap(ep,readin,n,LOOKAHEAD-n,mode)) { putstack(ep,readin,n,0); c = ep->e_lbuf[--ep->e_lookahead]; } else c = ed_getchar(ep,mode); ep->e_keytrap = 0; } else c = -c; } /*** map '\r' to '\n' ***/ if(c == '\r' && mode!=2) c = '\n'; if(ep->e_tabcount && !(c=='\t'||c==ESC || c=='\\' || c=='=' || c==cntl('L') || isdigit(c))) ep->e_tabcount = 0; } else siglongjmp(ep->e_env,(n==0?UEOF:UINTR)); return(c); }
void ed_setup(register Edit_t *ep, int fd, int reedit) { Shell_t *shp = ep->sh; register char *pp; register char *last, *prev; char *ppmax; int myquote = 0, n; register int qlen = 1, qwid; char inquote = 0; ep->e_fd = fd; ep->e_multiline = sh_isoption(SH_MULTILINE)!=0; #ifdef SIGWINCH if(!(shp->sigflag[SIGWINCH]&SH_SIGFAULT)) { signal(SIGWINCH,sh_fault); shp->sigflag[SIGWINCH] |= SH_SIGFAULT; } pp = shp->st.trapcom[SIGWINCH]; shp->st.trapcom[SIGWINCH] = 0; sh_fault(SIGWINCH); shp->st.trapcom[SIGWINCH] = pp; ep->sh->winch = 0; #endif #if SHOPT_EDPREDICT ep->hlist = 0; ep->nhlist = 0; ep->hoff = 0; #endif /* SHOPT_EDPREDICT */ #if KSHELL ep->e_stkptr = stakptr(0); ep->e_stkoff = staktell(); if(!(last = shp->prompt)) last = ""; shp->prompt = 0; #else last = ep->e_prbuff; #endif /* KSHELL */ if(shp->gd->hist_ptr) { register History_t *hp = shp->gd->hist_ptr; ep->e_hismax = hist_max(hp); ep->e_hismin = hist_min(hp); } else { ep->e_hismax = ep->e_hismin = ep->e_hloff = 0; } ep->e_hline = ep->e_hismax; if(!sh_isoption(SH_VI) && !sh_isoption(SH_EMACS) && !sh_isoption(SH_GMACS)) ep->e_wsize = MAXLINE; else ep->e_wsize = ed_window()-2; ep->e_winsz = ep->e_wsize+2; ep->e_crlf = 1; ep->e_plen = 0; pp = ep->e_prompt; ppmax = pp+PRSIZE-1; *pp++ = '\r'; { register int c; while(prev = last, c = mbchar(last)) switch(c) { case ESC: { int skip=0; ep->e_crlf = 0; *pp++ = c; for(n=1; c = *last++; n++) { if(pp < ppmax) *pp++ = c; if(c=='\a' || c==ESC || c=='\r') break; if(skip || (c>='0' && c<='9')) { skip = 0; continue; } if(n>1 && c==';') skip = 1; else if(n>2 || (c!= '[' && c!= ']')) break; } if(c==0 || c==ESC || c=='\r') last--; qlen += (n+1); break; } case '\b': if(pp>ep->e_prompt+1) pp--; break; case '\r': if(pp == (ep->e_prompt+2)) /* quote char */ myquote = *(pp-1); /*FALLTHROUGH*/ case '\n': /* start again */ ep->e_crlf = 1; qlen = 1; inquote = 0; pp = ep->e_prompt+1; break; case '\t': /* expand tabs */ while((pp-ep->e_prompt)%TABSIZE) { if(pp >= ppmax) break; *pp++ = ' '; } break; case '\a': /* cut out bells */ break; default: if(c==myquote) { qlen += inquote; inquote ^= 1; } if(pp < ppmax) { if(inquote) qlen++; else if(!is_print(c)) ep->e_crlf = 0; if((qwid = last - prev) > 1) qlen += qwid - mbwidth(c); while(prev < last && pp < ppmax) *pp++ = *prev++; } break; } } if(pp-ep->e_prompt > qlen) ep->e_plen = pp - ep->e_prompt - qlen; *pp = 0; if(!ep->e_multiline && (ep->e_wsize -= ep->e_plen) < 7) { register int shift = 7-ep->e_wsize; ep->e_wsize = 7; pp = ep->e_prompt+1; strcpy(pp,pp+shift); ep->e_plen -= shift; last[-ep->e_plen-2] = '\r'; } sfsync(sfstderr); if(fd == sffileno(sfstderr)) { /* can't use output buffer when reading from stderr */ static char *buff; if(!buff) buff = (char*)malloc(MAXLINE); ep->e_outbase = ep->e_outptr = buff; ep->e_outlast = ep->e_outptr + MAXLINE; return; } qlen = sfset(sfstderr,SF_READ,0); /* make sure SF_READ not on */ ep->e_outbase = ep->e_outptr = (char*)sfreserve(sfstderr,SF_UNBOUND,SF_LOCKR); ep->e_outlast = ep->e_outptr + sfvalue(sfstderr); if(qlen) sfset(sfstderr,SF_READ,1); sfwrite(sfstderr,ep->e_outptr,0); ep->e_eol = reedit; if(ep->e_multiline) { #ifdef _cmd_tput char *term; if(!ep->e_term) ep->e_term = nv_search("TERM",shp->var_tree,0); if(ep->e_term && (term=nv_getval(ep->e_term)) && strlen(term)<sizeof(ep->e_termname) && strcmp(term,ep->e_termname)) { sh_trap(".sh.subscript=$(tput cuu1 2>/dev/null)",0); if(pp=nv_getval(SH_SUBSCRNOD)) strncpy(CURSOR_UP,pp,sizeof(CURSOR_UP)-1); nv_unset(SH_SUBSCRNOD); strcpy(ep->e_termname,term); } #endif ep->e_wsize = MAXLINE - (ep->e_plen+1); } if(ep->e_default && (pp = nv_getval(ep->e_default))) { n = strlen(pp); if(n > LOOKAHEAD) n = LOOKAHEAD; ep->e_lookahead = n; while(n-- > 0) ep->e_lbuf[n] = *pp++; ep->e_default = 0; } }
/* signal handler for alarm call */ static void sigalrm(int sig) { register Timer_t *tp, *tplast, *tpold, *tpnext; double now; static double left; NOT_USED(sig); left = 0; if(time_state&SIGALRM_CALL) time_state &= ~SIGALRM_CALL; else if(alarm(0)) sh_fault(SIGALRM|SH_TRAP); if(time_state) { if(time_state&IN_ADDTIMEOUT) time_state |= DEFER_SIGALRM; errno = EINTR; return; } time_state |= IN_SIGALRM; sigrelease(SIGALRM); while(1) { now = getnow(); tpold = tpmin = 0; for(tplast=0,tp=tptop; tp; tp=tpnext) { tpnext = tp->next; if(tp->action) { if(tp->wakeup <=now) { if(!tpold || tpold->wakeup>tp->wakeup) tpold = tp; } else { if(!tpmin || tpmin->wakeup>tp->wakeup) tpmin=tp; } tplast = tp; } else { if(tplast) tplast->next = tp->next; else tptop = tp->next; tp->next = tpfree; tpfree = tp; } } if((tp=tpold) && tp->incr) { while((tp->wakeup += tp->incr) <= now); if(!tpmin || tpmin->wakeup>tp->wakeup) tpmin=tp; } if(tpmin && (left==0 || (tp && tpmin->wakeup < (now+left)))) { if(left==0) signal(SIGALRM,sigalrm); left = setalarm(tpmin->wakeup-now); if(left && (now+left) < tpmin->wakeup) setalarm(left); else left=tpmin->wakeup-now; } if(tp) { void (*action)(void*); action = tp->action; if(!tp->incr) tp->action = 0; errno = EINTR; time_state &= ~IN_SIGALRM; (*action)(tp->handle); time_state |= IN_SIGALRM; } else break; } if(!tpmin) signal(SIGALRM,(sh.sigflag[SIGALRM]&SH_SIGFAULT)?sh_fault:SIG_DFL); time_state &= ~IN_SIGALRM; errno = EINTR; }