1 /* @(#)edit.c 1.1 */
2
3 /*
4 * edit.c - common routines for vi and emacs one line editors in shell
5 *
6 * David Korn P.D. Sullivan
7 * AT&T Bell Laboratories AT&T Bell Laboratories
8 * Room 5D-112 Room 1E253
9 * Murray Hill, N. J. 07974 Columbus, OH 43213
10 * Tel. x7975 Tel. x 2655
11 *
12 * Coded April 1983.
13 */
14
15 #include <errno.h>
16
17 #ifdef KSHELL
18 #include "shtype.h"
19 #include "flags.h"
20 #include "defs.h"
21 #include "io.h"
22 #include "name.h"
23 #include "sym.h"
24 #include "stak.h"
25 #include "mode.h"
26 #include "builtins.h"
27 #include "brkincr.h"
28
29 #else
30 #include <stdio.h>
31 #include <signal.h>
32 #include <setjmp.h>
33 #include <ctype.h>
34 #endif /* KSHELL */
35
36 #include "history.h"
37 #include "edit.h"
38
39 #define BAD -1
40 #define GOOD 0
41 #define TRUE (-1)
42 #define FALSE 0
43 #define SYSERR -1
44
45 #ifdef VENIX
46 #define RT 1
47 #endif /* VENIX */
48
49 void e_crlf();
50 void e_flush();
51 int e_getchar();
52 void e_putchar();
53 void e_ringbell();
54 void e_setup();
55 int e_virt_to_phys();
56 int e_window();
57 void setcooked();
58 void ungetchar();
59
60 #if BSD || RT
61 #include <sgtty.h>
62 # ifdef BSD_4_2
63 # include <sys/time.h>
64 # endif /* BSD_4_2 */
65 static struct sgttyb ttyparm; /* initial tty parameters */
66 static struct sgttyb nttyparm; /* raw tty parameters */
67 # ifdef BSD
68 extern int tty_speeds[];
69 static int delay;
70 static int l_mask;
71 static struct tchars l_ttychars;
72 static struct ltchars l_chars;
73 static char l_changed; /* set if mode bits changed */
74 #define L_CHARS 4
75 #define T_CHARS 2
76 #define L_MASK 1
77 # endif /* BSD */
78 #else
79 # ifdef XENIX /* avoid symbol table overflows */
80 # define NCC 8
81 struct termio {
82 unsigned short c_iflag; /* input modes */
83 unsigned short c_oflag; /* output modes */
84 unsigned short c_cflag; /* control modes */
85 unsigned short c_lflag; /* line discipline modes */
86 char c_line; /* line discipline */
87 unsigned char c_cc[NCC]; /* control chars */
88 char c_res; /* padding, AFTER the array */
89 };
90 #define TIOC ('T'<<8)
91 #define BRKINT 0000002
92 #define CBAUD 0000017
93 #define ECHO 0000010
94 #define ECHOE 0000020
95 #define ECHOK 0000040
96 #define ECHONL 0000100
97 #define ICANON 0000002
98 #define ICRNL 0000400
99 #define IGNCR 0000200
100 #define IGNPAR 0000004
101 #define INLCR 0000100
102 #define PARMRK 0000010
103 #define TCGETA (TIOC|1)
104 #define TCSETAW (TIOC|3)
105 #define TCXONC (TIOC|6)
106 #define VEOF 4
107 #define VERASE 2
108 #define VKILL 3
109 #define VMIN 4
110 #define VTIME 5
111 #define TM_CECHO 0010
112 # else
113 # include <termio.h>
114 # endif /* XENIX */
115
116 static struct termio ttyparm; /* initial tty parameters */
117 static struct termio nttyparm; /* raw tty parameters */
118 #endif /* RT */
119
120 #define lookahead editb.e_index
121 #define env editb.e_env
122 #define previous editb.e_lbuf
123 #define fildes editb.e_fd
124
125 #ifdef KSHELL
126 extern struct Amemory *alias;
127 extern char **arg_build();
128 extern void failed();
129 extern void fault();
130 extern struct Namnod *findnod();
131 extern int f_complete();
132 extern void gsort();
133 extern char *movstr();
134 extern void p_flush();
135 extern void p_setout();
136 extern char *simple();
137 extern char *tilde();
138 extern char *valup();
139 static char macro[] = "_?";
140
141 #else
142 static char badcooked[] = "cannot reset tty to cooked mode";
143 struct edit editb;
144 char trapnote;
145 extern char trapnote;
146 extern int errno;
147 #define p_flush() fflush(stderr)
148 #define p_setout(s) fflush(stdout)
149 #define error(s) failed(s,NULL)
150 #define SIGSLOW 1
151 #define output stderr
152 #endif /* KSHELL */
153
154 extern char *strrchr();
155 extern char *strcpy();
156
157 static char bellchr[] = "\7"; /* bell char */
158
159 static int control();
160 /*{ SETCOOKED( fd )
161 *
162 * This routine will set the tty in cooked mode.
163 * It is also called by error.done().
164 *
165 }*/
166
setcooked(fd)167 void setcooked(fd)
168 register int fd;
169 {
170 /*** don't do ioctl unless ttyparm has valid data ***/
171 /* or in raw mode */
172
173 if(editb.e_ttyspeed==0 || editb.e_raw==0)
174 return;
175
176 #ifdef BSD
177 if(editb.e_raw==RAWMODE && ioctl(fd, TIOCSETN, &ttyparm) == SYSERR )
178 {
179 if(errno!=EBADF && errno!=ENOTTY)
180 error(badcooked);
181 return;
182 }
183 /* restore flags */
184 if(l_changed&L_MASK)
185 ioctl(fd,TIOCLSET,&l_mask);
186 if(l_changed&T_CHARS)
187 /* restore alternate break character */
188 ioctl(fd,TIOCSETC,&l_ttychars);
189 if(l_changed&L_CHARS)
190 /* restore alternate break character */
191 ioctl(fd,TIOCSLTC,&l_chars);
192 l_changed = 0;
193 #else
194 # ifdef RT
195 if (stty(fd,&ttyparm) == SYSERR)
196 # else
197 if( editb.e_raw && control(fd, TCSETAW, &ttyparm) == SYSERR )
198 # endif /* RT */
199 {
200 if(errno!=EBADF && errno!=ENOTTY)
201 error(badcooked);
202 return;
203 }
204 #endif /* BSD */
205 editb.e_raw = 0;
206 return;
207 }
208
209 /*{ SETRAW( fd )
210 *
211 * This routine will set the tty in raw mode.
212 *
213 }*/
214
setraw(fd)215 setraw(fd)
216 register int fd;
217 {
218 #ifdef BSD
219 struct ltchars lchars;
220 #endif /* BSD */
221 if(editb.e_raw==RAWMODE)
222 return(GOOD);
223 /* characters are echoed on standard error */
224 p_setout(stderr);
225 #if BSD || RT
226 # ifdef BSD
227 if((ioctl(fd,TIOCGETP,&ttyparm) == SYSERR)
228 # else
229 if ((gtty(fd,&ttyparm) == SYSERR)
230 # endif /* BSD */
231 || !(ttyparm.sg_flags & ECHO )
232 || (ttyparm.sg_flags & LCASE ))
233 {
234 return(BAD);
235 }
236 nttyparm = ttyparm;
237 nttyparm.sg_flags &= ~(ECHO | TBDELAY);
238 # ifdef BSD
239 nttyparm.sg_flags |= CBREAK;
240 # else
241 nttyparm.sg_flags |= RAW;
242 # endif /* BSD */
243 editb.e_erase = ttyparm.sg_erase;
244 editb.e_kill = ttyparm.sg_kill;
245 editb.e_eof = cntl(D);
246 # ifdef BSD
247 if( ioctl(fd, TIOCSETN, &nttyparm) == SYSERR )
248 # else
249 if( stty(fd, &nttyparm) == SYSERR )
250 # endif /* BSD */
251 {
252 return(BAD);
253 }
254 editb.e_ttyspeed = (ttyparm.sg_ospeed>=B1200?FAST:SLOW);
255 #ifdef BSD
256 delay = tty_speeds[ttyparm.sg_ospeed];
257 /* try to remove effect of ^V and ^Y */
258 if(ioctl(fd,TIOCGLTC,&l_chars) != SYSERR)
259 {
260 lchars = l_chars;
261 lchars.t_lnextc = -1;
262 lchars.t_dsuspc = -1; /* no delayed stop process signal */
263 if(ioctl(fd,TIOCSLTC,&lchars) != SYSERR)
264 l_changed |= L_CHARS;
265 }
266 #endif /* BSD */
267 #else
268
269 # ifndef RAWONLY
270 if(editb.e_raw != ALTMODE)
271 # endif /* RAWONLY */
272 if( (ioctl(fd, TCGETA, &ttyparm) == SYSERR)
273 || (!(ttyparm.c_lflag & ECHO )))
274 {
275 return(BAD);
276 }
277
278 nttyparm = ttyparm;
279 #ifndef u370
280 nttyparm.c_iflag &= ~(IGNPAR|PARMRK|INLCR|IGNCR|ICRNL);
281 nttyparm.c_iflag |= BRKINT;
282 nttyparm.c_lflag &= ~(ICANON|ECHO);
283 #else
284 nttyparm.c_iflag &=
285 ~(IGNBRK|PARMRK|INLCR|IGNCR|ICRNL|INPCK);
286 nttyparm.c_iflag |= (BRKINT|IGNPAR);
287 nttyparm.c_lflag &= ~(ICANON|ECHO);
288 #endif /* u370 */
289 nttyparm.c_cc[VTIME] = 0;
290 nttyparm.c_cc[VMIN] = 1;
291 editb.e_eof = ttyparm.c_cc[VEOF];
292 editb.e_erase = ttyparm.c_cc[VERASE];
293 editb.e_kill = ttyparm.c_cc[VKILL];
294 #ifndef u370
295 if( control(fd, TCSETAW, &nttyparm) == SYSERR )
296 #else
297 /* delays are too long, don't wait for output to drain */
298 if( control(fd, TCSETA, &nttyparm) == SYSERR )
299 #endif /* u370 */
300 {
301 return(BAD);
302 }
303 control(fd,TCXONC,1);
304 editb.e_ttyspeed = ttyparm.c_cflag & CBAUD;
305 #endif
306 editb.e_raw = RAWMODE;
307 return(GOOD);
308 }
309
310 #ifndef BSD
311 /*
312 * give two tries for ioctl
313 * interrupts are ignored
314 */
315
control(fd,request,arg)316 static int control(fd,request,arg)
317 {
318 register int i;
319 register int k = 2;
320 errno = 0;
321 while(k--)
322 {
323 if((i = ioctl(fd,request,arg)) != SYSERR)
324 return(i);
325 if(errno == EINTR)
326 {
327 errno = 0;
328 k++;
329 }
330 }
331 return(SYSERR);
332 }
333 #endif /* BSD */
334 #ifndef RAWONLY
335
336 /* SET_TTY( fd )
337 *
338 * Get tty parameters and make ESC and '\r' wakeup characters.
339 *
340 */
341
342 #ifdef BSD
setalt(fd)343 setalt(fd)
344 register int fd;
345 {
346 int mask;
347 struct tchars ttychars;
348 if(editb.e_raw==ALTMODE)
349 return(GOOD);
350 if(editb.e_raw==RAWMODE)
351 setcooked(fd);
352 l_changed = 0;
353 if( editb.e_ttyspeed == 0)
354 {
355 if((ioctl(fd,TIOCGETP,&ttyparm) != SYSERR))
356 editb.e_ttyspeed = (ttyparm.sg_ospeed>=B1200?FAST:SLOW);
357 }
358 if(ioctl(fd,TIOCGETC,&l_ttychars) == SYSERR)
359 return(BAD);
360 if(ioctl(fd,TIOCLGET,&l_mask)==SYSERR)
361 return(BAD);
362 ttychars = l_ttychars;
363 mask = LCRTBS|LCRTERA|LCTLECH|LPENDIN|LCRTKIL;
364 if((l_mask|mask) != l_mask)
365 l_changed = L_MASK;
366 if(ioctl(fd,TIOCLBIS,&mask)==SYSERR)
367 return(BAD);
368 ttychars.t_brkc = ESC;
369 l_changed |= T_CHARS;
370 if(ioctl(fd,TIOCSETC,&ttychars) == SYSERR)
371 return(BAD);
372 editb.e_raw = ALTMODE;
373 return(GOOD);
374 }
375 #else
setalt(fd)376 setalt(fd)
377 register int fd;
378 {
379 if(editb.e_raw==ALTMODE)
380 return(GOOD);
381 if(editb.e_raw==RAWMODE)
382 setcooked(fd);
383 if( (control(fd, TCGETA, &ttyparm) == SYSERR)
384 || (!(ttyparm.c_lflag & ECHO )))
385 {
386 return(BAD);
387 }
388 nttyparm = ttyparm;
389 nttyparm.c_iflag &= ~(IGNCR|ICRNL);
390 nttyparm.c_iflag |= INLCR;
391 nttyparm.c_lflag |= (ECHOE|ECHOK);
392 nttyparm.c_cc[VEOF] = ESC; /* make ESC the eof char */
393 nttyparm.c_cc[VEOL] = '\r'; /* make CR an eol char */
394 editb.e_eof = ttyparm.c_cc[VEOF];
395 nttyparm.c_cc[VEOL2] = editb.e_eof; /* make EOF an eol char */
396 editb.e_erase = ttyparm.c_cc[VERASE];
397 editb.e_kill = ttyparm.c_cc[VKILL];
398 if( control(fd, TCSETAW, &nttyparm) == SYSERR )
399 {
400 return(BAD);
401 }
402 editb.e_ttyspeed = ((ttyparm.c_cflag&CBAUD)>=B1200?FAST:SLOW);
403 editb.e_raw = ALTMODE;
404 return(GOOD);
405 }
406
407 #endif /* BSD */
408 #endif /* RAWONLY */
409
410 /*
411 * E_WINDOW()
412 *
413 * return the window size
414 */
415
e_window()416 int e_window()
417 {
418 register int n = DFLTWINDOW-1;
419 register char *cp = valup(COLUMNS);
420 if(cp)
421 {
422 n = atoi(cp)-1;
423 if(n < MINWINDOW)
424 n = MINWINDOW;
425 if(n > MAXWINDOW)
426 n = MAXWINDOW;
427 }
428 return(n);
429 }
430
431 /* E_FLUSH()
432 *
433 * Flush the output buffer.
434 *
435 */
436
e_flush()437 void e_flush()
438 {
439 register unsigned char *buf = (unsigned char*)output->_base;
440 register int n = editb.e_outptr-buf;
441 register int fd = fileno(output);
442 if(n<=0)
443 return;
444 write(fd,(char*)buf,n);
445 editb.e_outptr = buf;
446 #ifdef BSD
447 # ifdef BSD_4_2
448 if(delay && n > delay/100)
449 {
450 /* delay until output drains */
451 struct timeval timeloc;
452 n *= 10;
453 timeloc.tv_sec = n/delay;
454 timeloc.tv_usec = (1000000*(n%delay))/delay;
455 select(0,0,0,0,&timeloc);
456 }
457 # endif /* BSD_4_2 */
458 #else
459 # ifndef RT
460 if(editb.e_raw==RAWMODE && n > 16)
461 ioctl(fd, TCSETAW, &nttyparm);
462 # endif /* RT */
463 #endif /* BSD */
464 }
465
466 /*
467 * send the bell character ^G to the terminal
468 */
469
e_ringbell()470 void e_ringbell()
471 {
472 write(fileno(output),bellchr,1);
473 }
474
475 /*
476 * send a carriage return line feed to the terminal
477 */
478
e_crlf()479 void e_crlf()
480 {
481 #ifdef u370
482 e_putchar('\r');
483 #endif /* u370 */
484 #ifdef VENIX
485 e_putchar('\r');
486 #endif /* VENIX */
487 e_putchar('\n');
488 e_flush();
489 }
490
491 /* E_SETUP( max_prompt_size )
492 *
493 * This routine sets up the prompt string
494 */
495
e_setup(fd,PRSIZE)496 void e_setup(fd,PRSIZE)
497 {
498 register char *last;
499 register char *pp = (char*)(output->_base);
500 char *ppmax;
501 editb.e_fd = fd;
502 if(fc_fix)
503 {
504 register struct fixcmd *fp = fc_fix;
505 editb.e_hismax = fp->fixind;
506 editb.e_hloff = fp->fixline;
507 editb.e_hismin = fp->fixind-fp->fixmax;
508 if(editb.e_hismin<0)
509 editb.e_hismin = 0;
510 }
511 else
512 {
513 editb.e_hismax = editb.e_hismin = editb.e_hloff = 0;
514 }
515 editb.e_hline = editb.e_hismax;
516 editb.e_wsize = e_window()-2;
517 editb.e_outptr = (unsigned char*)pp;
518 editb.e_crlf = YES;
519 *(output->_ptr) = 0;
520 if((last=strrchr(pp,'\n'))==NULL)
521 {
522 if(*(last=pp)==0)
523 editb.e_crlf = NO;
524 }
525 else
526 last++;
527 pp = editb.e_prompt;
528 ppmax = pp+PRSIZE-1;
529 *pp++ = '\r';
530 {
531 register int c;
532 while(c = *last++)
533 {
534 /* cut out bells */
535 if(c!=BELL)
536 {
537 if(pp < ppmax)
538 *pp++ = c;
539 if(!isprint(c))
540 editb.e_crlf = NO;
541 }
542 }
543 }
544 editb.e_plen = pp - editb.e_prompt - 1;
545 *pp = 0;
546 #ifdef u370
547 if (editb.e_raw == RAWMODE)
548 u370fflush(output);
549 else
550 #endif /* u370 */
551 p_flush();
552 }
553
554 #ifdef u370
555 /* The u370 does not \r before \n in raw mode (known bug).
556 To get around this we will insert a \r before each \n
557 in the output buffer.
558 */
559
u370fflush(file)560 u370fflush(file)
561 FILE *file;
562 {
563 unsigned char *base,*ptr,buffer[BUFSIZ*2];
564 int icnt,ocnt;
565 ptr = buffer;
566 icnt = file->_ptr - file->_base;
567 ocnt = icnt;
568 base = file->_base ;
569 if (icnt <= 0) return;
570 while (base < file->_ptr)
571 {
572 if (*base == '\n' )
573 {
574 *ptr++ = '\r';
575 ocnt++;
576 }
577 *ptr++ = *base++;
578 }
579 base = file->_base;
580 ptr = buffer;
581 while (ocnt>0)
582 {
583 for(icnt=0;icnt<BUFSIZ;icnt++)
584 {
585 *base++ = *ptr++;
586 if (--ocnt <= 0) break;
587 }
588 file->_ptr = base;
589 p_flush();
590 base = file->_base;
591 }
592 }
593 #endif /* u370 */
594
595 #ifdef KSHELL
596 /*
597 * look for edit macro named _i
598 * if found, puts the macro definition into lookahead buffer and returns 1
599 */
600
e_macro(i)601 e_macro(i)
602 register int i;
603 {
604 register char *out;
605 struct Namnod *np;
606 genchar buff[LOOKAHEAD+1];
607 if(i != '@')
608 macro[1] = i;
609 if (isalnum(i)&&(np=findnod(macro,alias,0))&&(out=valup(np)))
610 {
611 #ifdef MULTIBYTE
612 /* copy to buff in internal representation */
613 int c = out[LOOKAHEAD];
614 out[LOOKAHEAD] = 0;
615 i = e_internal(out,buff);
616 out[LOOKAHEAD] = c;
617 #else
618 strncpy((char*)buff,out,LOOKAHEAD);
619 i = strlen((char*)buff);
620 #endif /* MULTIBYTE */
621 while(i-- > 0)
622 ungetchar(buff[i]);
623 return(1);
624 }
625 return(0);
626 }
627 /*
628 * file name generation for edit modes
629 * non-zero exit for error, <0 ring bell
630 * don't search back past <start> character of the buffer
631 * mode is '*' for inline expansion, otherwise files are listed in select format
632 */
633
q_expand(outbuff,cur,eol,start,mode)634 q_expand(outbuff,cur,eol,start,mode)
635 char outbuff[];
636 int *cur;
637 int *eol;
638 int start;
639 int mode;
640 {
641 STKPTR staksav = stakbot;
642 COMPTR comptr = (COMPTR)getstak(COMTYPE);
643 ARGPTR ap = (ARGPTR)locstak();
644 register char *out;
645 char *outmin = outbuff + start;
646 char *begin;
647 char *last;
648 int rval = 0;
649 int strip;
650 optflag savflags = flags;
651 #ifdef MULTIBYTE
652 {
653 register int c = *cur;
654 register genchar *cp;
655 /* adjust cur */
656 cp = (genchar *)outbuff + *cur;
657 c = *cp;
658 *cp = 0;
659 *cur = e_external((genchar*)outbuff,(char*)stakbot);
660 *cp = c;
661 *eol = e_external((genchar*)outbuff,outbuff);
662 }
663 #endif /* MULTIBYTE */
664 out = outbuff + *cur;
665 comptr->comtyp = COMSCAN;
666 comptr->comarg = ap;
667 ap->argflag = (A_MAC|A_EXP);
668 ap->argnxt = 0;
669 {
670 register int c;
671 register char *ptr = ap->argval;
672 int chktilde = 0;
673 int flag;
674 char *cp;
675 if(out>outmin)
676 {
677 /* go to beginning of word */
678 do
679 {
680 out--;
681 c = *(unsigned char*)out;
682 }
683 while(out>outmin && !isqmeta(c));
684 /* copy word into arg */
685 if(isqmeta(c))
686 out++;
687 }
688 else
689 out = outmin;
690 begin = out;
691 flag = '*';
692 strip = TRUE;
693 /* copy word to arg and do ~ expansion */
694 do
695 {
696 c = *(unsigned char*)out++;
697 if(isexp(c))
698 flag = 0;
699 if ((c == '/') && (flag == 0))
700 strip = FALSE;
701 *ptr++ = c;
702 if(chktilde==0 && (c==0 || c == '/'))
703 {
704 chktilde++;
705 if(cp=tilde(begin))
706 {
707 ptr = movstr(cp,ap->argval);
708 *ptr++ = c;
709 }
710 }
711
712 } while (c && !isqmeta(c));
713
714 out--;
715 *(ptr-1) = flag;
716 endstak(ptr);
717 last = ptr-1;
718 }
719 if(mode!='*')
720 on_option(MARKDIR);
721 {
722 register char **com;
723 int narg;
724 register int size;
725 while(1)
726 {
727 com = arg_build(&narg,comptr);
728 /* match? */
729 if (narg > 1 || !eq(ap->argval,*com))
730 break;
731 if (*last == 0)
732 *last = '*';
733 else
734 {
735 rval = -1;
736 goto done;
737 }
738 }
739 if(mode!='*')
740 {
741 if (strip)
742 {
743 register char **ptrcom;
744 for(ptrcom=com;*ptrcom;ptrcom++)
745 /* trim directory prefix */
746 *ptrcom = simple (*ptrcom);
747 }
748 p_setout(stderr);
749 newline();
750 p_list(narg,com);
751 p_flush();
752 goto done;
753 }
754 /* see if there is enough room */
755 size = *eol - (out-begin);
756 size += narg;
757 {
758 char **savcom = com;
759 while (*com)
760 size += strlen(*com++);
761 com = savcom;
762 }
763 /* see if room for expansion */
764 if(outbuff+size >= &outbuff[MAXLINE])
765 {
766 com[0] = ap->argval;
767 com[1] = NULL;
768 }
769 /* save remainder of the buffer */
770 strcpy(stakbot,out);
771 out = begin;
772 while (*com)
773 {
774 out = movstr(*com,out);
775 if (*++com)
776 *out++ = ' ';
777 }
778 *cur = (out-outbuff);
779 /* restore rest of buffer */
780 out = movstr(stakbot,out);
781 *eol = (out-outbuff);
782 }
783 done:
784 tdystak(staksav);
785 flags = savflags;
786 #ifdef MULTIBYTE
787 {
788 register int c;
789 /* first re-adjust cur */
790 out = outbuff + *cur;
791 c = *out;
792 *out = 0;
793 *cur = e_internal(outbuff,(genchar*)stakbot);
794 *out = c;
795 outbuff[*eol+1] = 0;
796 *eol = e_internal(outbuff,(genchar*)outbuff);
797 }
798 #endif /* MULTIBYTE */
799 return(rval);
800 }
801 #endif /* KSHELL */
802
803
804 /*
805 * routine to perform read from terminal for vi and emacs mode
806 */
807
808
809 int
e_getchar()810 e_getchar()
811 {
812 register int i;
813 register int c;
814 register int maxtry = 100;
815 int nchar; /* number of characters to read at a time */
816 #ifdef MULTIBYTE
817 static int curchar;
818 static int cursize;
819 #endif /* MULTIBYTE */
820 char readin[LOOKAHEAD] ;
821 if (lookahead)
822 {
823 c = previous[--lookahead];
824 /*** map '\r' to '\n' ***/
825 if(c == '\r')
826 c = '\n';
827 return(c);
828 }
829
830 e_flush() ;
831 /* you can't chance read ahead at the end of line */
832 nchar = (editb.e_cur>=editb.e_eol?1:READAHEAD);
833 /* Set 'i' to indicate read failed, in case intr set */
834 retry:
835 i = -1;
836 errno = 0;
837 editb.e_inmacro = 0;
838 while((trapnote&SIGSLOW)==0 && maxtry--)
839 {
840 errno=0;
841 if ((i = read(fildes,readin, nchar)) != -1)
842 break;
843 }
844 #ifdef MULTIBYTE
845 lookahead = maxtry = i;
846 i = 0;
847 while (i < maxtry)
848 {
849 c = readin[i++] & STRIP;
850 next:
851 if(cursize-- > 0)
852 {
853 curchar = (curchar<<7) | (c&~HIGHBIT);
854 if(cursize==0)
855 {
856 c = curchar;
857 goto gotit;
858 }
859 else if(i>=maxtry)
860 goto retry;
861 continue;
862 }
863 else if(curchar = echarset(c))
864 {
865 cursize = in_csize(curchar);
866 if(curchar != 1)
867 c = 0;
868 curchar <<= 7*(ESS_MAXCHAR-cursize);
869 if(c)
870 goto next;
871 else if(i>=maxtry)
872 goto retry;
873 continue;
874 }
875 gotit:
876 previous[--lookahead] = c;
877 #else
878 while (i > 0)
879 {
880 c = readin[--i] & STRIP;
881 previous[lookahead++] = c;
882 #endif /* MULTIBYTE */
883 #ifndef BSD
884 if( c == '\0' )
885 {
886 /*** user break key ***/
887 lookahead = 0;
888 # ifdef KSHELL
889 fault(SIGINT);
890 longjmp(env, UINTR);
891 # endif /* KSHELL */
892 }
893 #endif /* !BSD */
894 }
895 #ifdef MULTIBYTE
896 /* shift lookahead buffer if necessary */
897 if(lookahead)
898 {
899 for(i=lookahead;i < maxtry;i++)
900 previous[i-lookahead] = previous[i];
901 }
902 lookahead = maxtry-lookahead;
903 #endif /* MULTIBYTE */
904 if (lookahead > 0)
905 return(e_getchar(1));
906 longjmp(env,(i==0?UEOF:UINTR)); /* What a mess! Give up */
907 /* NOTREACHED */
908 }
909
910 void ungetchar(c)
911 register int c;
912 {
913 if (lookahead < LOOKAHEAD)
914 previous[lookahead++] = c;
915 return;
916 }
917
918 /*
919 * put a character into the output buffer
920 */
921
922 void e_putchar(c)
923 register int c;
924 {
925 register unsigned char *dp = editb.e_outptr;
926 #ifdef MULTIBYTE
927 register int d;
928 /* check for place holder */
929 if(c == MARKER)
930 return;
931 if(d = icharset(c))
932 {
933 if(d == 2)
934 *dp++ = ESS2;
935 else if(d == 3)
936 *dp++ = ESS3;
937 d = in_csize(d);
938 while(--d>0)
939 *dp++ = HIGHBIT|(c>>(7*d));
940 c |= HIGHBIT;
941 }
942 #endif /* MULTIBYTE */
943 if (c == '_')
944 {
945 *dp++ = ' ';
946 *dp++ = '\b';
947 }
948 *dp++ = c;
949 *dp = '\0';
950 if ((dp - (unsigned char*)(output->_base))>=(BUFSIZ-3))
951 e_flush();
952 else
953 editb.e_outptr = dp;
954 }
955
956 /*
957 * copy virtual to physical and return the index for cursor in physical buffer
958 */
959 e_virt_to_phys(virt,phys,cur,voff,poff)
960 genchar *virt;
961 genchar *phys;
962 int cur;
963 {
964 register genchar *sp = virt;
965 register genchar *dp = phys;
966 register int c;
967 genchar *curp = sp + cur;
968 genchar *dpmax = phys+MAXLINE;
969 int r = 0;
970 #ifdef MULTIBYTE
971 int d;
972 #endif /* MULTIBYTE */
973 sp += voff;
974 dp += poff;
975 for(r=poff;c= *sp;sp++)
976 {
977 if(curp == sp)
978 r = dp - phys;
979 #ifdef MULTIBYTE
980 d = out_csize(icharset(c));
981 if(d>1)
982 {
983 /* multiple width character put in place holders */
984 *dp++ = c;
985 while(--d >0)
986 *dp++ = MARKER;
987 /* in vi mode the cursor is at the last character */
988 if(dp>=dpmax)
989 break;
990 continue;
991 }
992 else
993 #endif /* MULTIBYTE */
994 if(!isprint(c))
995 {
996 if(c=='\t')
997 {
998 c = dp-phys;
999 c = ((c+8)&~07) - c;
1000 while(--c>0)
1001 *dp++ = ' ';
1002 c = ' ';
1003 }
1004 else
1005 {
1006 *dp++ = '^';
1007 c ^= TO_PRINT;
1008 }
1009 /* in vi mode the cursor is at the last character */
1010 if(curp == sp && is_option(EDITVI))
1011 r = dp - phys;
1012 }
1013 *dp++ = c;
1014 if(dp>=dpmax)
1015 break;
1016 }
1017 *dp = 0;
1018 return(r);
1019 }
1020
1021 #ifdef MULTIBYTE
1022 /*
1023 * convert external representation <src> to an array of genchars <dest>
1024 * <src> and <dest> can be the same
1025 * returns number of chars in dest
1026 */
1027
1028 int e_internal(src,dest)
1029 register unsigned char *src;
1030 genchar *dest;
1031 {
1032 register int c;
1033 register genchar *dp = dest;
1034 register int d;
1035 register int size;
1036 if((unsigned char*)dest == src)
1037 {
1038 genchar buffer[MAXLINE];
1039 c = e_internal(src,buffer);
1040 e_gencpy(dp,buffer);
1041 return(c);
1042 }
1043 while(c = *src++)
1044 {
1045 if(size = echarset(c))
1046 {
1047 d = (size==1?c:0);
1048 c = size;
1049 size = in_csize(c);
1050 c <<= 7*(ESS_MAXCHAR-size);
1051 if(d)
1052 {
1053 size--;
1054 c = (c<<7) | (d&~HIGHBIT);
1055 }
1056 while(size-- >0)
1057 c = (c<<7) | ((*src++)&~HIGHBIT);
1058 }
1059 *dp++ = c;
1060 }
1061 *dp = 0;
1062 return(dp-dest);
1063 }
1064
1065 /*
1066 * convert internal representation <src> into character array <dest>.
1067 * The <src> and <dest> may be the same.
1068 * returns number of chars in dest.
1069 */
1070
1071 int e_external(src,dest)
1072 genchar *src;
1073 char *dest;
1074 {
1075 register int c;
1076 register char *dp = dest;
1077 register int d;
1078 char *dpmax = dp+sizeof(genchar)*MAXLINE-2;
1079 if((char*)src == dp)
1080 {
1081 char buffer[MAXLINE*sizeof(genchar)];
1082 c = e_external(src,buffer);
1083 strcpy(dest,buffer);
1084 return(c);
1085 }
1086 while((c = *src++) && dp<dpmax)
1087 {
1088 if(d = icharset(c))
1089 {
1090 if(d == 2)
1091 *dp++ = ESS2;
1092 else if(d == 3)
1093 *dp++ = ESS3;
1094 d = in_csize(d);
1095 while(--d>0)
1096 *dp++ = HIGHBIT|(c>>(7*d));
1097 c |= HIGHBIT;
1098 }
1099 *dp++ = c;
1100 }
1101 *dp = 0;
1102 return(dp-dest);
1103 }
1104
1105 /*
1106 * copy <sp> to <dp>
1107 */
1108
1109 int e_gencpy(dp,sp)
1110 register genchar *dp;
1111 register genchar *sp;
1112 {
1113 while(*dp++ = *sp++);
1114 }
1115
1116 /*
1117 * copy at most <n> items from <sp> to <dp>
1118 */
1119
1120 int e_genncpy(dp,sp, n)
1121 register genchar *dp;
1122 register genchar *sp;
1123 register int n;
1124 {
1125 while(n-->0 && (*dp++ = *sp++));
1126 }
1127
1128 /*
1129 * find the string length of <str>
1130 */
1131
1132 int e_genlen(str)
1133 register genchar *str;
1134 {
1135 register genchar *sp = str;
1136 while(*sp++);
1137 return(sp-str-1);
1138 }
1139 #endif /* MULTIBYTE */
1140