/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */ /* All Rights Reserved */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */ /* UNIX System Laboratories, Inc. */ /* The copyright notice above does not evidence any */ /* actual or intended publication of such source code. */ #ident "@(#)ksh:sh/edit.c 1.6.4.2" /* * edit.c - common routines for vi and emacs one line editors in shell * * David Korn P.D. Sullivan * AT&T Bell Laboratories AT&T Bell Laboratories * Room 3C-526B Room 1B-286 * Murray Hill, N. J. 07974 Columbus, OH 43213 * Tel. x7975 Tel. x 2655 * * Coded April 1983. */ #include #ifdef KSHELL # include "defs.h" # include "terminal.h" # include "builtins.h" # include "sym.h" #else # include "io.h" # include "terminal.h" # undef SIG_NORESTART # define SIG_NORESTART 1 # define _sobuf ed_errbuf extern char ed_errbuf[]; char e_version[] = "\n@(#)Editlib version 11/16/88f\0\n"; #endif /* KSHELL */ #include "history.h" #include "edit.h" #define BAD -1 #define GOOD 0 #define TRUE (-1) #define FALSE 0 #define SYSERR -1 #ifdef OLDTERMIO # undef tcgetattr # undef tcsetattr #endif /* OLDTERMIO */ #ifdef RT # define VENIX 1 #endif /* RT */ #define lookahead editb.e_index #define env editb.e_env #define previous editb.e_lbuf #define fildes editb.e_fd #define in_raw editb.e_addnl #ifdef _sgtty_ # ifdef TIOCGETP static int l_mask; static struct tchars l_ttychars; static struct ltchars l_chars; static char l_changed; /* set if mode bits changed */ # define L_CHARS 4 # define T_CHARS 2 # define L_MASK 1 # endif /* TIOCGETP */ #endif /* _sgtty_ */ #ifndef IODELAY # undef _SELECT5_ #endif /* IODELAY */ #ifdef _SELECT5_ # ifndef included_sys_time_ # include # endif /* included_sys_time_ */ static int delay; # ifndef KSHELL int tty_speeds[] = {0, 50, 75, 110, 134, 150, 200, 300, 600,1200,1800,2400,9600,19200,0}; # endif /* KSHELL */ #endif /* _SELECT5_ */ #ifdef KSHELL extern char *sh_tilde(); static char macro[] = "_??"; # define slowsig() (sh.trapnote&SIGSLOW) #else struct edit editb; extern int errno; # define slowsig() (0) #endif /* KSHELL */ void ed_gencpy(); static struct termios savetty; static int savefd = -1; #ifdef future static int compare(); #endif #if VSH || ESH extern char *strrchr(); extern char *strcpy(); static struct termios ttyparm; /* initial tty parameters */ static struct termios nttyparm; /* raw tty parameters */ static char bellchr[] = "\7"; /* bell char */ # define tenex 1 # ifdef tenex static char *overlay(); # endif /* tenex */ #endif /* VSH || ESH */ /* * This routine returns true if fd refers to a terminal * This should be equivalent to isatty */ int tty_check(fd) { return(tty_get(fd,(struct termios*)0)==0); } /* * Get the current terminal attributes * This routine remembers the attributes and just returns them if it * is called again without an intervening tty_set() */ int tty_get(fd, tty) struct termios *tty; { if(fd != savefd) { #ifndef SIG_NORESTART VOID (*savint)() = st.intfn; st.intfn = 0; #endif /* SIG_NORESTART */ while(tcgetattr(fd,&savetty) == SYSERR) { if(errno !=EINTR) { #ifndef SIG_NORESTART st.intfn = savint; #endif /* SIG_NORESTART */ return(SYSERR); } errno = 0; } #ifndef SIG_NORESTART st.intfn = savint; #endif /* SIG_NORESTART */ savefd = fd; } if(tty) *tty = savetty; return(0); } /* * Set the terminal attributes * If fd<0, then current attributes are invalidated */ /* VARARGS 2 */ int tty_set(fd, action, tty) struct termios *tty; { if(fd >=0) { #ifndef SIG_NORESTART VOID (*savint)() = st.intfn; #endif /* SIG_NORESTART */ #ifdef future if(savefd>=0 && compare(&savetty,tty,sizeof(struct termios))) return(0); #endif #ifndef SIG_NORESTART st.intfn = 0; #endif /* SIG_NORESTART */ while(tcsetattr(fd, action, tty) == SYSERR) { if(errno !=EINTR) { #ifndef SIG_NORESTART st.intfn = savint; #endif /* SIG_NORESTART */ return(SYSERR); } errno = 0; } #ifndef SIG_NORESTART st.intfn = savint; #endif /* SIG_NORESTART */ savetty = *tty; } savefd = fd; return(0); } #if ESH || VSH /*{ TTY_COOKED( fd ) * * This routine will set the tty in cooked mode. * It is also called by error.done(). * }*/ void tty_cooked(fd) register int fd; { if(editb.e_raw==0) return; if(fd < 0) fd = savefd; #ifdef L_MASK /* restore flags */ if(l_changed&L_MASK) ioctl(fd,TIOCLSET,&l_mask); if(l_changed&T_CHARS) /* restore alternate break character */ ioctl(fd,TIOCSETC,&l_ttychars); if(l_changed&L_CHARS) /* restore alternate break character */ ioctl(fd,TIOCSLTC,&l_chars); l_changed = 0; #endif /* L_MASK */ /*** don't do tty_set unless ttyparm has valid data ***/ if(savefd<0 || tty_set(fd, TCSANOW, &ttyparm) == SYSERR) return; editb.e_raw = 0; return; } /*{ TTY_RAW( fd ) * * This routine will set the tty in raw mode. * }*/ tty_raw(fd) register int fd; { #ifdef L_MASK struct ltchars lchars; #endif /* L_MASK */ if(editb.e_raw==RAWMODE) return(GOOD); #ifndef RAWONLY if(editb.e_raw != ALTMODE) #endif /* RAWONLY */ { if(tty_get(fd,&ttyparm) == SYSERR) return(BAD); } #if L_MASK || VENIX if(!(ttyparm.sg_flags&ECHO) || (ttyparm.sg_flags&LCASE)) return(BAD); nttyparm = ttyparm; nttyparm.sg_flags &= ~(ECHO | TBDELAY); # ifdef CBREAK nttyparm.sg_flags |= CBREAK; # else nttyparm.sg_flags |= RAW; # endif /* CBREAK */ editb.e_erase = ttyparm.sg_erase; editb.e_kill = ttyparm.sg_kill; editb.e_eof = cntl('D'); if( tty_set(fd, TCSADRAIN, &nttyparm) == SYSERR ) return(BAD); editb.e_ttyspeed = (ttyparm.sg_ospeed>=B1200?FAST:SLOW); # ifdef _SELECT5_ delay = tty_speeds[ttyparm.sg_ospeed]; # endif /* _SELECT5_ */ # ifdef TIOCGLTC /* try to remove effect of ^V and ^Y and ^O */ if(ioctl(fd,TIOCGLTC,&l_chars) != SYSERR) { lchars = l_chars; lchars.t_lnextc = -1; lchars.t_flushc = -1; lchars.t_dsuspc = -1; /* no delayed stop process signal */ if(ioctl(fd,TIOCSLTC,&lchars) != SYSERR) l_changed |= L_CHARS; } # endif /* TIOCGLTC */ #else if (!(ttyparm.c_lflag & ECHO )) return(BAD); # ifdef FLUSHO ttyparm.c_lflag &= ~FLUSHO; # endif /* FLUSHO */ nttyparm = ttyparm; # ifndef u370 nttyparm.c_iflag &= ~(IGNPAR|PARMRK|INLCR|IGNCR|ICRNL); nttyparm.c_iflag |= BRKINT; nttyparm.c_lflag &= ~(ICANON|ECHO); # else nttyparm.c_iflag &= ~(IGNBRK|PARMRK|INLCR|IGNCR|ICRNL|INPCK); nttyparm.c_iflag |= (BRKINT|IGNPAR); nttyparm.c_lflag &= ~(ICANON|ECHO); # endif /* u370 */ nttyparm.c_cc[VTIME] = 0; nttyparm.c_cc[VMIN] = 1; # ifdef VDISCARD nttyparm.c_cc[VDISCARD] = 0; # endif /* VDISCARD */ editb.e_eof = ttyparm.c_cc[VEOF]; editb.e_erase = ttyparm.c_cc[VERASE]; editb.e_kill = ttyparm.c_cc[VKILL]; if( tty_set(fd, TCSADRAIN, &nttyparm) == SYSERR ) return(BAD); editb.e_ttyspeed = (cfgetospeed(&ttyparm)>=B1200?FAST:SLOW); #endif editb.e_raw = RAWMODE; return(GOOD); } #ifndef RAWONLY /* * * Get tty parameters and make ESC and '\r' wakeup characters. * */ # ifdef TIOCGETC tty_alt(fd) register int fd; { int mask; struct tchars ttychars; if(editb.e_raw==ALTMODE) return(GOOD); if(editb.e_raw==RAWMODE) tty_cooked(fd); l_changed = 0; if( editb.e_ttyspeed == 0) { if((tty_get(fd,&ttyparm) != SYSERR)) editb.e_ttyspeed = (ttyparm.sg_ospeed>=B1200?FAST:SLOW); editb.e_raw = ALTMODE; } if(ioctl(fd,TIOCGETC,&l_ttychars) == SYSERR) return(BAD); if(ioctl(fd,TIOCLGET,&l_mask)==SYSERR) return(BAD); ttychars = l_ttychars; mask = LCRTBS|LCRTERA|LCTLECH|LPENDIN|LCRTKIL; if((l_mask|mask) != l_mask) l_changed = L_MASK; if(ioctl(fd,TIOCLBIS,&mask)==SYSERR) return(BAD); if(ttychars.t_brkc!=ESC) { ttychars.t_brkc = ESC; l_changed |= T_CHARS; if(ioctl(fd,TIOCSETC,&ttychars) == SYSERR) return(BAD); } return(GOOD); } # else # ifndef PENDIN # define PENDIN 0 # endif /* PENDIN */ # ifndef IEXTEN # define IEXTEN 0 # endif /* IEXTEN */ tty_alt(fd) register int fd; { if(editb.e_raw==ALTMODE) return(GOOD); if(editb.e_raw==RAWMODE) tty_cooked(fd); if((tty_get(fd, &ttyparm)==SYSERR) || (!(ttyparm.c_lflag&ECHO))) return(BAD); # ifdef FLUSHO ttyparm.c_lflag &= ~FLUSHO; # endif /* FLUSHO */ nttyparm = ttyparm; editb.e_eof = ttyparm.c_cc[VEOF]; # ifdef ECHOCTL /* escape character echos as ^[ */ nttyparm.c_lflag |= (ECHOE|ECHOK|ECHOCTL|PENDIN|IEXTEN); nttyparm.c_cc[VEOL2] = ESC; # else /* switch VEOL2 and EOF, since EOF isn't echo'd by driver */ nttyparm.c_iflag &= ~(IGNCR|ICRNL); nttyparm.c_iflag |= INLCR; nttyparm.c_lflag |= (ECHOE|ECHOK); nttyparm.c_cc[VEOF] = ESC; /* make ESC the eof char */ nttyparm.c_cc[VEOL] = '\r'; /* make CR an eol char */ nttyparm.c_cc[VEOL2] = editb.e_eof; /* make EOF an eol char */ # endif /* ECHOCTL */ # ifdef VWERASE nttyparm.c_cc[VWERASE] = cntl('W'); # endif /* VWERASE */ # ifdef VLNEXT nttyparm.c_cc[VLNEXT] = cntl('V'); # endif /* VLNEXT */ editb.e_erase = ttyparm.c_cc[VERASE]; editb.e_kill = ttyparm.c_cc[VKILL]; if( tty_set(fd, TCSADRAIN, &nttyparm) == SYSERR ) return(BAD); editb.e_ttyspeed = (cfgetospeed(&ttyparm)>=B1200?FAST:SLOW); editb.e_raw = ALTMODE; return(GOOD); } # endif /* TIOCGETC */ #endif /* RAWONLY */ /* * E_WINDOW() * * return the window size */ #ifndef WINSIZE # undef TIOCGWINSZ #endif /* !WINSIZE */ #ifdef TIOCGWINSZ # ifdef _sys_stream_ # include # endif /* _sys_ptem_ */ #ifdef _sys_ptem_ # include #endif /* _sys_stream_ */ #else # ifdef _sys_jioctl_ # include # define winsize jwinsize # define ws_col bytesx # define TIOCGWINSZ JWINSIZE # endif /* _sys_jioctl_ */ #endif /*TIOCGWINSZ */ int ed_window() { register int n = DFLTWINDOW-1; register char *cp = nam_strval(COLUMNS); if(cp) { n = atoi(cp)-1; if(n > MAXWINDOW) n = MAXWINDOW; } #ifdef TIOCGWINSZ else { /* for 5620's and 630's */ struct winsize size; if (ioctl(ERRIO, TIOCGWINSZ, &size) != -1) if(size.ws_col > 0) n = size.ws_col - 1; } #endif /*TIOCGWINSZ */ if(n < MINWINDOW) n = MINWINDOW; return(n); } /* E_FLUSH() * * Flush the output buffer. * */ void ed_flush() { register int n = editb.e_outptr-editb.e_outbase; register int fd = ERRIO; if(n<=0) return; write(fd,editb.e_outbase,(unsigned)n); editb.e_outptr = editb.e_outbase; #ifdef _SELECT5_ if(delay && n > delay/100) { /* delay until output drains */ struct timeval timeloc; n *= 10; timeloc.tv_sec = n/delay; timeloc.tv_usec = (1000000*(n%delay))/delay; select(0,(fd_set*)0,(fd_set*)0,(fd_set*)0,&timeloc); } #else # ifdef IODELAY if(editb.e_raw==RAWMODE && n > 16) tty_set(fd, TCSADRAIN, &nttyparm); # endif /* IODELAY */ #endif /* _SELECT5_ */ } /* * send the bell character ^G to the terminal */ void ed_ringbell() { write(ERRIO,bellchr,1); } /* * send a carriage return line feed to the terminal */ void ed_crlf() { #ifdef cray ed_putchar('\r'); #endif /* cray */ #ifdef u370 ed_putchar('\r'); #endif /* u370 */ #ifdef VENIX ed_putchar('\r'); #endif /* VENIX */ ed_putchar('\n'); ed_flush(); } /* E_SETUP( max_prompt_size ) * * This routine sets up the prompt string * The following is an unadvertised feature. * Escape sequences in the prompt can be excluded from the calculated * prompt length. This is accomplished as follows: * - if the prompt string starts with "%\r, or contains \r%\r", where % * represents any char, then % is taken to be the quote character. * - strings enclosed by this quote character, and the quote character, * are not counted as part of the prompt length. */ void ed_setup(fd) { register char *pp; register char *last; char *ppmax; int myquote = 0; int qlen = 1; char inquote = 0; editb.e_fd = fd; p_setout(ERRIO); #ifdef KSHELL last = _sobuf; #else last = editb.e_prbuff; #endif /* KSHELL */ if(hist_ptr) { register struct history *fp = hist_ptr; editb.e_hismax = fp->fixind; editb.e_hloff = 0; editb.e_hismin = fp->fixind-fp->fixmax; if(editb.e_hismin<0) editb.e_hismin = 0; } else { editb.e_hismax = editb.e_hismin = editb.e_hloff = 0; } editb.e_hline = editb.e_hismax; editb.e_wsize = ed_window()-2; editb.e_crlf = (*last?YES:NO); pp = editb.e_prompt; ppmax = pp+PRSIZE-1; *pp++ = '\r'; { register int c; while(c= *last++) switch(c) { case '\r': if(pp == (editb.e_prompt+2)) /* quote char */ myquote = *(pp-1); /*FALLTHROUGH*/ case '\n': /* start again */ editb.e_crlf = YES; qlen = 1; inquote = 0; pp = editb.e_prompt+1; break; case '\t': /* expand tabs */ while(((pp-editb.e_prompt)%TABSIZE) && pp[c evoke alias __c */ if(i=='_') macro[2] = ed_getchar(); else macro[2] = 0; if (isalnum(i)&&(np=nam_search(macro,sh.alias_tree,N_NOSCOPE))&&(out=nam_strval(np))) { #ifdef MULTIBYTE /* copy to buff in internal representation */ int c = out[LOOKAHEAD]; out[LOOKAHEAD] = 0; i = ed_internal(out,buff); out[LOOKAHEAD] = c; #else strncpy((char*)buff,out,LOOKAHEAD); i = strlen((char*)buff); #endif /* MULTIBYTE */ while(i-- > 0) ed_ungetchar(buff[i]); return(1); } return(0); } /* * file name generation for edit modes * non-zero exit for error, <0 ring bell * don't search back past beginning of the buffer * mode is '*' for inline expansion, * mode is '\' for filename completion * mode is '=' cause files to be listed in select format */ ed_expand(outbuff,cur,eol,mode) char outbuff[]; int *cur; int *eol; int mode; { char *staksav = stakptr(0); struct comnod *comptr = (struct comnod*)stakalloc(sizeof(struct comnod)); struct argnod *ap = (struct argnod*)stakseek(ARGVAL); register char *out; char *begin; int addstar; int istilde = 0; int rval = 0; int strip; optflag savflags = opt_flags; #ifdef MULTIBYTE { register int c = *cur; register genchar *cp; /* adjust cur */ cp = (genchar *)outbuff + *cur; c = *cp; *cp = 0; *cur = ed_external((genchar*)outbuff,(char*)stakptr(0)); *cp = c; *eol = ed_external((genchar*)outbuff,outbuff); } #endif /* MULTIBYTE */ out = outbuff + *cur; comptr->comtyp = COMSCAN; comptr->comarg = ap; ap->argflag = (A_MAC|A_EXP); ap->argchn = 0; ap->argnxt.ap = 0; { register int c; int chktilde; char *cp; if(out>outbuff) { /* go to beginning of word */ do { out--; c = *(unsigned char*)out; } while(out>outbuff && !isqmeta(c)); /* copy word into arg */ if(isqmeta(c)) out++; } else out = outbuff; begin = out; chktilde = (*out=='~'); /* addstar set to zero if * should not be added */ addstar = '*'; strip = TRUE; /* copy word to arg and do ~ expansion */ do { c = *(unsigned char*)out; if(isexp(c)) addstar = 0; if ((c == '/') && (addstar == 0)) strip = FALSE; stakputc(c); if(chktilde && (c==0 || c == '/')) { chktilde=0; *out = 0; if(cp=sh_tilde(begin)) { istilde++; stakseek(ARGVAL); stakputs(cp); stakputc(c); if(c==0) { addstar = 0; strip = FALSE; } } *out = c; } out++; } while (c && !isqmeta(c)); out--; #ifdef tenex if(mode=='\\') addstar = '*'; #endif /* tenex */ *stakptr(staktell()-1) = addstar; stakfreeze(1); } if(mode!='*') on_option(MARKDIR); { register char **com; int narg; register int size; VOID (*savfn)(); savfn = st.intfn; com = arg_build(&narg,comptr); st.intfn = savfn; /* match? */ if (*com==0 || (!istilde && narg <= 1 && eq(ap->argval,*com))) { rval = -1; goto done; } if(mode=='=') { if (strip) { register char **ptrcom; for(ptrcom=com;*ptrcom;ptrcom++) /* trim directory prefix */ *ptrcom = path_basename(*ptrcom); } p_setout(ERRIO); newline(); p_list(narg,com); p_flush(); goto done; } /* see if there is enough room */ size = *eol - (out-begin); #ifdef tenex if(mode=='\\') { /* just expand until name is unique */ size += strlen(*com); } else #endif { size += narg; { char **savcom = com; while (*com) size += strlen(*com++); com = savcom; } } /* see if room for expansion */ if(outbuff+size >= &outbuff[MAXLINE]) { com[0] = ap->argval; com[1] = 0; } /* save remainder of the buffer */ strcpy(stakptr(0),out); out = sh_copy(*com++, begin); #ifdef tenex if(mode=='\\') { if(*com==0 && out[-1]!='/') *out++ = ' '; while (*com && *begin) out = overlay(begin,*com++); if(*begin==0) ed_ringbell(); } else #endif while (*com) { *out++ = ' '; out = sh_copy(*com++,out); } *cur = (out-outbuff); /* restore rest of buffer */ out = sh_copy(stakptr(0),out); *eol = (out-outbuff); } done: stakset(staksav,0); opt_flags = savflags; #ifdef MULTIBYTE { register int c; /* first re-adjust cur */ out = outbuff + *cur; c = *out; *out = 0; *cur = ed_internal(outbuff,(genchar*)stakptr(0)); *out = c; outbuff[*eol+1] = 0; *eol = ed_internal(outbuff,(genchar*)outbuff); } #endif /* MULTIBYTE */ return(rval); } # ifdef tenex static char *overlay(str,newstr) register char *str,*newstr; { while(*str && *str == *newstr++) str++; *str = 0; return(str); } # endif /* * Enter the fc command on the current history line */ ed_fulledit() { register char *cp; register int i; if(!hist_ptr || (st.states&BUILTIN)) return(BAD); /* use EDITOR on current command */ if(editb.e_hline == editb.e_hismax) { if(editb.e_eol<=0) return(BAD); editb.e_inbuf[editb.e_eol+1] = 0; p_setout(hist_ptr->fixfd); /* Do not use p_str() because it also writes the terminating null char */ /* p_str((char*)editb.e_inbuf,0); */ for(i=0;i<=editb.e_eol;++i) p_char(editb.e_inbuf[i]); st.states |= FIXFLG; hist_flush(); } cp = sh_copy(e_runvi, (char*)editb.e_inbuf); cp = sh_copy(sh_itos(editb.e_hline), cp); editb.e_eol = (unsigned char*)cp - (unsigned char*)editb.e_inbuf; return(GOOD); } #endif /* KSHELL */ /* * routine to perform read from terminal for vi and emacs mode */ int ed_getchar() { register int i; register int c; register int maxtry = MAXTRY; unsigned nchar = READAHEAD; /* number of characters to read at a time */ #ifdef MULTIBYTE static int curchar; static int cursize; #endif /* MULTIBYTE */ char readin[LOOKAHEAD] ; if (lookahead) { c = previous[--lookahead]; /*** map '\r' to '\n' ***/ if(c == '\r' && !in_raw) c = '\n'; return(c); } ed_flush() ; /* * you can't chance read ahead at the end of line * or when the input is a pipe */ #ifdef KSHELL if((editb.e_cur>=editb.e_eol) || fnobuff(io_ftable[fildes])) #else if(editb.e_cur>=editb.e_eol) #endif /* KSHELL */ nchar = 1; /* Set 'i' to indicate read failed, in case intr set */ retry: i = -1; errno = 0; editb.e_inmacro = 0; while(slowsig()==0 && maxtry--) { errno=0; if ((i = read(fildes,readin, nchar)) != -1) break; else if (errno == EINTR) { #ifdef JOBS if (is_option(NOTIFY)) job_wait((pid_t)0); #endif /* JOBS */ } } #ifdef MULTIBYTE lookahead = maxtry = i; i = 0; while (i < maxtry) { c = readin[i++] & STRIP; next: if(cursize-- > 0) { curchar = (curchar<<7) | (c&~HIGHBIT); if(cursize==0) { c = curchar; goto gotit; } else if(i>=maxtry) goto retry; continue; } else if(curchar = echarset(c)) { cursize = in_csize(curchar); if(curchar != 1) c = 0; curchar <<= 7*(ESS_MAXCHAR-cursize); if(c) goto next; else if(i>=maxtry) goto retry; continue; } gotit: previous[--lookahead] = c; #else while (i > 0) { c = readin[--i] & STRIP; previous[lookahead++] = c; #endif /* MULTIBYTE */ #ifndef CBREAK if( c == '\0' ) { /*** user break key ***/ lookahead = 0; # ifdef KSHELL sh_fault(SIGINT); LONGJMP(env, UINTR); # endif /* KSHELL */ } #endif /* !CBREAK */ } #ifdef MULTIBYTE /* shift lookahead buffer if necessary */ if(lookahead) { for(i=lookahead;i < maxtry;i++) previous[i-lookahead] = previous[i]; } lookahead = maxtry-lookahead; #endif /* MULTIBYTE */ if (lookahead > 0) return(ed_getchar()); LONGJMP(env,(i==0?UEOF:UINTR)); /* What a mess! Give up */ /* NOTREACHED */ } void ed_ungetchar(c) register int c; { if (lookahead < LOOKAHEAD) previous[lookahead++] = c; return; } /* * put a character into the output buffer */ void ed_putchar(c) register int c; { register char *dp = editb.e_outptr; #ifdef MULTIBYTE register int d; /* check for place holder */ if(c == MARKER) return; if(d = icharset(c)) { if(d == 2) *dp++ = ESS2; else if(d == 3) *dp++ = ESS3; d = in_csize(d); while(--d>0) *dp++ = HIGHBIT|(c>>(7*d)); c |= HIGHBIT; } #endif /* MULTIBYTE */ if (c == '_') { *dp++ = ' '; *dp++ = '\b'; } *dp++ = c; *dp = '\0'; if(dp >= editb.e_outlast) ed_flush(); else editb.e_outptr = dp; } /* * copy virtual to physical and return the index for cursor in physical buffer */ ed_virt_to_phys(virt,phys,cur,voff,poff) genchar *virt; genchar *phys; int cur; { register genchar *sp = virt; register genchar *dp = phys; register int c; genchar *curp = sp + cur; genchar *dpmax = phys+MAXLINE; int r; #ifdef MULTIBYTE int d; #endif /* MULTIBYTE */ sp += voff; dp += poff; for(r=poff;c= *sp;sp++) { if(curp == sp) r = dp - phys; #ifdef MULTIBYTE d = out_csize(icharset(c)); if(d>1) { /* multiple width character put in place holders */ *dp++ = c; while(--d >0) *dp++ = MARKER; /* in vi mode the cursor is at the last character */ if(dp>=dpmax) break; continue; } else #endif /* MULTIBYTE */ if(!isprint(c)) { if(c=='\t') { c = dp-phys; if(is_option(EDITVI)) c += editb.e_plen; c = TABSIZE - c%TABSIZE; while(--c>0) *dp++ = ' '; c = ' '; } else { *dp++ = '^'; c ^= TO_PRINT; } /* in vi mode the cursor is at the last character */ if(curp == sp && is_option(EDITVI)) r = dp - phys; } *dp++ = c; if(dp>=dpmax) break; } *dp = 0; return(r); } #ifdef MULTIBYTE /* * convert external representation to an array of genchars * and can be the same * returns number of chars in dest */ int ed_internal(src,dest) register unsigned char *src; genchar *dest; { register int c; #if sgi genchar buffer[MAXLINE]; register genchar *dp = buffer; #else register genchar *dp = dest; #endif register int d; register int size; #ifndef sgi if((unsigned char*)dest == src) { genchar buffer[MAXLINE]; c = ed_internal(src,buffer); ed_gencpy(dp,buffer); return(c); } #endif while(c = *src++) { if(size = echarset(c)) { d = (size==1?c:0); c = size; size = in_csize(c); c <<= 7*(ESS_MAXCHAR-size); if(d) { size--; c = (c<<7) | (d&~HIGHBIT); } while(size-- >0) c = (c<<7) | ((*src++)&~HIGHBIT); } *dp++ = c; } *dp = 0; #if sgi ed_gencpy(dest, buffer); return(dp-buffer); #else return(dp-dest); #endif } /* * convert internal representation into character array . * The and may be the same. * returns number of chars in dest. */ int ed_external(src,dest) genchar *src; char *dest; { register int c; register char *dp = dest; register int d; char *dpmax = dp+sizeof(genchar)*MAXLINE-2; if((char*)src == dp) { char buffer[MAXLINE*sizeof(genchar)]; c = ed_external(src,buffer); strcpy(dest,buffer); return(c); } while((c = *src++) && dp0) *dp++ = HIGHBIT|(c>>(7*d)); c |= HIGHBIT; } *dp++ = c; } *dp = 0; return(dp-dest); } /* * copy to */ void ed_gencpy(dp,sp) register genchar *dp; register genchar *sp; { while(*dp++ = *sp++); } /* * copy at most items from to */ void ed_genncpy(dp,sp, n) register genchar *dp; register genchar *sp; register int n; { while(n-->0 && (*dp++ = *sp++)); } /* * find the string length of */ int ed_genlen(str) register genchar *str; { register genchar *sp = str; while(*sp++); return(sp-str-1); } #endif /* MULTIBYTE */ #endif /* ESH || VSH */ #ifdef MULTIBYTE /* * set the multibyte widths * format of string is x1[:y1][,x2[:y2][,x3[:y3]]] * returns 1 if string in not in this format, 0 otherwise. */ extern char int_charsize[]; ed_setwidth(string) char *string; { register int indx = 0; register int state = 0; register int c; register int n = 0; static char widths[6] = {1,1}; while(1) switch(c = *string++) { case ':': if(state!=1) return(1); state++; /* fall through */ case 0: case ',': if(state==0) return(1); widths[indx++] = n; if(state==1) widths[indx++] = n; if(c==0) { for(n=1;n<= 3;n++) { int_charsize[n] = widths[c++]; int_charsize[n+4] = widths[c++]; } return(0); } else if(c==',') state = 0; n = 0; break; case '0': case '1': case '2': case '3': case '4': if(state&1) return(1); n = c - '0'; state++; break; default: return(1); } /* NOTREACHED */ } #endif /* MULTIBYTE */ #ifdef future /* * returns 1 when bytes starting at and are equal */ static int compare(a,b,n) register char *a; register char *b; register int n; { while(n-->0) { if(*a++ != *b++) return(0); } return(1); } #endif #ifdef OLDTERMIO # include #ifndef ECHOCTL # define ECHOCTL 0 #endif /* !ECHOCTL */ char echoctl; static char tcgeta; static struct termio ott; /* * For backward compatibility only * This version will use termios when possible, otherwise termio */ tcgetattr(fd,tt) struct termios *tt; { register int r; register int i; tcgeta = 0; echoctl = (ECHOCTL!=0); if((r=ioctl(fd,TCGETS,tt))>=0 || errno!=EINVAL) return(r); if((r=ioctl(fd,TCGETA,&ott)) >= 0) { tt->c_lflag = ott.c_lflag; tt->c_oflag = ott.c_oflag; tt->c_iflag = ott.c_iflag; tt->c_cflag = ott.c_cflag; for(i=0; ic_cc[i] = ott.c_cc[i]; tcgeta++; echoctl = 0; } return(r); } tcsetattr(fd,mode,tt) register int mode; struct termios *tt; { register int r; if(tcgeta) { register int i; ott.c_lflag = tt->c_lflag; ott.c_oflag = tt->c_oflag; ott.c_iflag = tt->c_iflag; ott.c_cflag = tt->c_cflag; for(i=0; ic_cc[i]; if(tt->c_lflag&ECHOCTL) { ott.c_lflag &= ~(ECHOCTL|IEXTEN); ott.c_iflag &= ~(IGNCR|ICRNL); ott.c_iflag |= INLCR; ott.c_cc[VEOF]= ESC; /* ESC -> eof char */ ott.c_cc[VEOL] = '\r'; /* CR -> eol char */ ott.c_cc[VEOL2] = tt->c_cc[VEOF]; /* EOF -> eol char */ } switch(mode) { case TCSANOW: mode = TCSETA; break; case TCSADRAIN: mode = TCSETAW; break; case TCSAFLUSH: mode = TCSETAF; } return(ioctl(fd,mode,&ott)); } return(ioctl(fd,mode,tt)); } #endif /* OLDTERMIO */