added checking of result when building demos
[urisagit/Stem.git] / extras / ssfe.c
CommitLineData
3e03d89e 1/* An ircII-like split-screen front end
2 Copyright (C) 1995 Roger Espel Llima
3
4 Started: 17 Feb 95 by orabidoo <roger.espel.llima@ens.fr>
5 Latest modification: 7 June 97
6
7 To compile: gcc ssfe.c -o ssfe -ltermcap
8
9 If it doesn't work, try gcc ssfe.c -o ssfe -lcurses
10 or try cc, acc or c89 instead of gcc, or -lncurses.
11
12 Use: ssfe [options] program arguments
13
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation. See the file LICENSE for details.
17*/
18
19#include <sys/time.h>
20#include <sys/types.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <fcntl.h>
24#include <unistd.h>
25#include <signal.h>
26#include <errno.h>
27
28#ifdef USE_SGTTY
29#include <sgtty.h>
30#else
31#include <termios.h>
32#endif
33
34#include <sys/ioctl.h>
35
36#ifdef _AIX
37#include <sys/select.h>
38#endif
39
40#define BUF_SIZE 512
41#define MAX_COLS 512
42
43unsigned char *statusline;
44int ystatus, yinput; /* line number of the status line, input line */
45
46int ttyfd;
47#ifdef TIOCGWINSZ
48struct winsize wsz;
49#endif
50
51#ifdef USE_SGTTY
52struct sgttyb term, term0;
53struct tchars tch, tch0;
54struct ltchars lch, lch0;
55#else
56struct termios term, term0;
57#endif
58
59int pid, mypid;
60int i;
61int cols, lines;
62int readfd, writefd, errfd;
63
64unsigned char *t, *w;
65unsigned char tmpstr[BUF_SIZE], extrainput[BUF_SIZE+20], readbuf[2*BUF_SIZE],
66 *input, *writebuf, o_buffer[BUF_SIZE];
67int bold=0, inv=0, under=0, wherex=0, wherey=0, donl=0;
68int hold_mode=0, hold_lines=0, ctrlx=0, beep=0, flow=0;
69
70unsigned char defprompt[]="> ",
71 nullstring[]="",
72 *prompt;
73int plen=0, specialprompt=0, modified=1, no_echo=0;
74
75#define MAX_TAB_LINES 20
76struct tabinfo {
77 unsigned char string[BUF_SIZE];
78 struct tabinfo *prev, *next;
79};
80int tablines=0;
81struct tabinfo *curtabt=NULL, *curtabr=NULL, *oldest=NULL;
82
83#define MAX_HIST_LINES 50
84struct histinfo {
85 unsigned char string[BUF_SIZE+20];
86 int len, plen;
87 struct histinfo *prev, *next;
88};
89int histlines=0;
90struct histinfo *histcurrent=NULL, *histoldest=NULL;
91
92char ctrl_t[128] = "/next\n";
93
94unsigned char id[]="`#ssfe#", *inid=id, protcmd[BUF_SIZE], *wpc=protcmd;
95int idstatus=0; /* 0 looking for/in the word, 1 in the arguments */
96#define ID_BACK "@ssfe@"
97
98int rc, rrc, inputcursor, inputlast, inputofs, inarrow=0, quote=0;
99int cursorwhere; /* 0 = up, 1 = down, 2 = undef */
100int dispmode=1; /* 0=raw, 1=wordwrap, 2=process ^b^v^_ */
101int printmode=0;
102int cutline=0;
103
104char *termtype, termcap[1024], *tc, capabilities[2048];
105char *t_cm, *t_cl, *t_mr, *t_md, *t_me, *t_cs, *t_ce, *t_us;
106int ansi_cs = 0;
107
108fd_set ready, result;
109extern int errno;
110
111#ifdef __GNUC__
112extern unsigned char *tgoto(unsigned char *cm, int col, int line);
113#else
114extern unsigned char *tgoto();
115#endif
116
117#ifdef __GNUC__
118int myputchar(int c) {
119#else
120int myputchar(c) {
121#endif
122 unsigned char cc=(unsigned char)c;
123 return(write(1, &cc, 1));
124}
125
126#ifdef __GNUC__
127int addchar(int c) {
128#else
129int addchar(c) {
130#endif
131 (*w++)=(unsigned char)c;
132}
133
134#ifdef __GNUC__
135void putcap(unsigned char *s) {
136#else
137void putcap(s)
138unsigned char *s; {
139#endif
140 tputs(s, 0, myputchar);
141}
142
143#ifdef __GNUC__
144int do_cs(int y1, int y2) {
145#else
146int do_cs(y1, y2) {
147#endif
148 static char temp[16];
149 if (ansi_cs) {
150 sprintf(temp, "\e[%d;%dr", y1, y2);
151 write(1, temp, strlen(temp));
152 } else putcap((char *)tgoto(t_cs, y2-1, y1-1));
153}
154
155#ifdef __GNUC__
156void writecap(unsigned char *s) {
157#else
158void writecap(s)
159unsigned char *s; {
160#endif
161 tputs(s, 0, addchar);
162}
163
164#ifdef __GNUC__
165void gotoxy(int x, int y) {
166#else
167void gotoxy(x, y) {
168#endif
169/* left upper = 0, 0 */
170 putcap(tgoto(t_cm, x, y));
171}
172
173#define clearscreen() (putcap(t_cl))
174#define cleareol() (putcap(t_ce))
175#define fullscroll() (do_cs(0, 0))
176#define winscroll() (do_cs(1, lines-2))
177#define setbold() (putcap(t_md))
178#define setunder() (putcap(t_us))
179#define setinv() (putcap(t_mr))
180#define normal() (putcap(t_me))
181
182#ifdef __GNUC__
183void ofsredisplay(int x);
184void inschar(unsigned char t);
185void dokbdchar(unsigned char t);
186#else
187void ofsredisplay();
188void inschar();
189void dokbdchar();
190#endif
191void displaystatus();
192
193#ifdef __GNUC__
194void cleanupexit(int n, unsigned char *error) {
195#else
196void cleanupexit(n, error)
197int n;
198unsigned char *error; {
199#endif
200 normal();
201 fullscroll();
202 gotoxy(0, lines-1);
203 cleareol();
204#ifdef USE_SGTTY
205 ioctl(ttyfd, TIOCSETP, &term0);
206 ioctl(ttyfd, TIOCSETC, &tch0);
207 ioctl(ttyfd, TIOCSLTC, &lch0);
208#else
209 tcsetattr(ttyfd, TCSADRAIN, &term0);
210#endif
211 close(ttyfd);
212 if (error!=NULL)
213 fprintf(stderr, "%s\n", error);
214 exit(n);
215}
216
217void allsigs();
218
219void interrupted() {
220 cleanupexit(1, "interrupted");
221}
222
223void sigpipe() {
224 cleanupexit(1, "program died");
225}
226
227void sigcont() {
228 allsigs();
229#ifdef USE_SGTTY
230 ioctl(ttyfd, TIOCSETP, &term);
231 ioctl(ttyfd, TIOCSETC, &tch);
232 ioctl(ttyfd, TIOCSLTC, &lch);
233#else
234 tcsetattr(ttyfd, TCSANOW, &term);
235#endif
236 wherex=0;
237 wherey=ystatus-1;
238 displaystatus();
239 ofsredisplay(0);
240}
241
242void suspend() {
243 normal();
244 fullscroll();
245 gotoxy(0, ystatus);
246 cleareol();
247#ifdef USE_SGTTY
248 ioctl(ttyfd, TIOCSETP, &term0);
249 ioctl(ttyfd, TIOCSETC, &tch0);
250 ioctl(ttyfd, TIOCSLTC, &lch0);
251#else
252 tcsetattr(ttyfd, TCSANOW, &term0);
253#endif
254 kill(pid, SIGCONT);
255 signal(SIGTSTP, SIG_DFL);
256 signal(SIGCONT, sigcont);
257 kill(mypid, SIGTSTP);
258}
259
260void sigwinch() {
261#ifdef TIOCGWINSZ
262 signal(SIGWINCH, sigwinch);
263 if (ioctl(ttyfd, TIOCGWINSZ, &wsz)>=0 && wsz.ws_row>0 && wsz.ws_col>0) {
264 lines=wsz.ws_row;
265 cols=wsz.ws_col;
266 cursorwhere=2;
267 ystatus=lines-2;
268 yinput=lines-1;
269 wherex=0;
270 wherey=ystatus-1;
271 displaystatus();
272 if (inputlast>cols-8) {
273 inputcursor=cols-9;
274 inputofs=inputlast-cols+9;
275 } else {
276 inputofs=0;
277 inputcursor=inputlast;
278 }
279 ofsredisplay(0);
280 }
281#endif
282}
283
284void allsigs() {
285 signal(SIGHUP, interrupted);
286 signal(SIGINT, interrupted);
287 signal(SIGQUIT, SIG_IGN);
288 signal(SIGPIPE, sigpipe);
289 signal(SIGTSTP, suspend);
290 signal(SIGCONT, sigcont);
291#ifdef TIOCGWINSZ
292 signal(SIGWINCH, sigwinch);
293#endif
294}
295
296#ifdef __GNUC__
297void setstatus(unsigned char *title) {
298#else
299void setstatus(title)
300unsigned char *title; {
301#endif
302 unsigned char *t=title;
303 for (;*t;t++) if (*t<' ') (*t)+='@';
304 memset(statusline, ' ', MAX_COLS-1);
305 memcpy(statusline, title, strlen(title)<MAX_COLS ? strlen(title) : MAX_COLS);
306}
307
308void displaystatus() {
309 normal();
310 fullscroll();
311 gotoxy(0, ystatus);
312 setinv();
313 write(1, statusline, cols-1);
314 if (hold_mode) {
315 gotoxy(cols-4, ystatus);
316 write(1, "(h)", 3);
317 }
318 cursorwhere=2;
319 normal();
320 cleareol();
321}
322
323#ifdef __GNUC__
324int casecmp(unsigned char *s, unsigned char *t) {
325#else
326int casecmp(s, t)
327unsigned char *s, *t; {
328#endif
329 while (((*s>='a' && *s<='z')?(*s)-32:*s)==
330 ((*t>='a' && *t<='z')?(*t)-32:*t)) {
331 if (*s=='\0') return 1;
332 s++; t++;
333 }
334 return 0;
335}
336
337#ifdef __GNUC__
338void addtab(unsigned char *line) {
339#else
340void addtab(line)
341unsigned char *line; {
342#endif
343 struct tabinfo *nt;
344
345 nt=oldest;
346 if (tablines) do {
347 if (casecmp(nt->string, line)) {
348 strcpy(nt->string, line);
349 if (nt==oldest) oldest=nt->prev;
350 else {
351 nt->prev->next=nt->next;
352 nt->next->prev=nt->prev;
353 nt->prev=oldest;
354 nt->next=oldest->next;
355 oldest->next=nt;
356 nt->next->prev=nt;
357 }
358 curtabt=oldest->next;
359 curtabr=oldest;
360 return;
361 }
362 nt=nt->next;
363 } while (nt!=oldest);
364
365 if (!tablines) {
366 nt=(struct tabinfo *)malloc(sizeof (struct tabinfo));
367 nt->prev=nt->next=curtabt=curtabr=oldest=nt;
368 tablines++;
369 } else if (tablines<MAX_TAB_LINES) {
370 nt=(struct tabinfo *)malloc(sizeof (struct tabinfo));
371 nt->prev=oldest;
372 nt->next=oldest->next;
373 oldest->next=nt;
374 nt->next->prev=nt;
375 tablines++;
376 } else {
377 nt=oldest;
378 oldest=nt->prev;
379 }
380 strcpy(nt->string, line);
381 oldest=nt->prev;
382 curtabt=oldest->next;
383 curtabr=oldest;
384}
385
386void doprotcommand() {
387 unsigned char *tmp;
388
389 switch (protcmd[0]) {
390 case 'i' : dispmode=2; /* set irc mode, ack */
391 bold=inv=under=0;
392 write(writefd, "@ssfe@i\n", 8);
393 break;
394 case 'c' : dispmode=1; /* set cooked mode, ack */
395 write(writefd, "@ssfe@c\n", 8);
396 break;
397 case 's' : setstatus(protcmd+1); /* set status */
398 displaystatus();
399 break;
400 case 'T' : strncpy(ctrl_t, protcmd+1, 127); /* set ^t's text */
401 ctrl_t[126] = '\0';
402 strcat(ctrl_t, "\n");
403 break;
404 case 't' : addtab(protcmd+1); /* add tabkey entry */
405 break;
406 case 'l' : fullscroll(); /* clear screen */
407 normal();
408 clearscreen();
409 bold=inv=under=wherex=wherey=donl=0;
410 displaystatus();
411 ofsredisplay(0);
412 break;
413
414 case 'P' : no_echo = 1; /* password prompt */
415 case 'p' : if (strlen(protcmd+1)<=8) { /* prompt something */
416 fullscroll();
417 if (!specialprompt) {
418 histcurrent->len=inputlast;
419 histcurrent->plen=plen;
420 }
421 input=extrainput;
422 strcpy(input, protcmd+1);
423 plen=strlen(input);
424 inputofs=0;
425 modified=specialprompt=1;
426 inputlast=inputcursor=plen;
427 ofsredisplay(0);
428 }
429 break;
430 case 'n' : if (cursorwhere!=1) { /* type text */
431 normal();
432 fullscroll();
433 gotoxy(inputcursor, yinput);
434 cursorwhere=1;
435 }
436 for (tmp=protcmd+1; *tmp; tmp++) {
437 inschar(*tmp);
438 }
439 break;
440 case 'o' : strcpy(o_buffer, protcmd+1);
441 break;
442 }
443}
444
445void newline() {
446 unsigned char t;
447 hold_lines++;
448 if (hold_mode && hold_lines>lines-4) {
449 normal();
450 fullscroll();
451 gotoxy(cols-4, ystatus);
452 setinv();
453 write(1, "(H)", 3);
454 while(1) {
455 read(0, &t, 1);
456 if (t==9) break;
457 dokbdchar(t);
458 }
459 normal();
460 fullscroll();
461 gotoxy(cols-4, ystatus);
462 setinv();
463 write(1, "(h)", 3);
464 hold_lines=0;
465 normal();
466 winscroll();
467 gotoxy(cols-1, wherey);
468 if (bold) setbold();
469 if (under) setunder();
470 if (inv) setinv();
471 }
472}
473
474#ifdef __GNUC__
475void formatter(unsigned char *readbuf, int rc) {
476#else
477void formatter(readbuf, rc)
478unsigned char *readbuf;
479int rc; {
480#endif
481
482 unsigned char t, *r, *lwr, *lww;
483 int lwrc, lwbold, lwunder, lwinv, lwx;
484
485 if (cursorwhere!=0) {
486 winscroll();
487 gotoxy(wherex, wherey);
488 cursorwhere=0;
489 }
490 if (donl) {
491 newline();
492 write(1, "\r\n", 2);
493 normal();
494 wherex=0;
495 bold=inv=under=lwbold=lwinv=lwunder=0;
496 if (wherey<ystatus-1) wherey++;
497 } else if (dispmode>1) {
498 if (bold) setbold();
499 if (under) setunder();
500 if (inv) setinv();
501 lwbold=bold;
502 lwinv=inv;
503 lwunder=under;
504 }
505 if (rc && readbuf[rc-1]=='\n') {
506 rc--;
507 donl=1; cutline=0;
508 } else {
509 donl=0;
510 if (dispmode==0) cutline=1;
511 }
512 if (dispmode==0) {
513 if (rc) write(1, readbuf, rc);
514 normal();
515 return;
516 }
517 lww=w=writebuf;
518 lwr=r=readbuf;
519 lwrc=rc;
520 lwx=wherex;
521 while(rc-->0) {
522 t=(*r++);
523 if (t=='\r') continue;
524 if (wherex>cols-2 || (t==9 && wherex>(cols-2)&0xfff8)) {
525 if (t==' ' || t==9) ;
526 else if (lww>writebuf+cols/2) {
527 wherex=lwx; r=lwr; w=lww; rc=lwrc;
528 bold=lwbold; inv=lwinv; under=lwunder; wherex=lwx;
529 } else {
530 rc++; r--;
531 }
532 write(1, writebuf, w-writebuf);
533 newline();
534 write(1, "\r\n ", 13);
535 w=writebuf;
536 lwr=r; lww=w; lwrc=rc;
537 lwbold=bold; lwinv=inv; lwunder=under;
538 lwx=wherex=11;
539 if (wherey<ystatus-1) wherey++;
540 rc--; t=(*r++);
541 }
542 if (t=='\n') {
543 if (w!=writebuf) write(1, writebuf, w-writebuf);
544 newline();
545 write(1, "\r\n", 2);
546 normal();
547 w=writebuf;
548 lwr=r; lww=w; lwrc=rc;
549 lwbold=bold=lwinv=inv=lwunder=under=lwx=wherex=0;
550 if (wherey<ystatus-1) wherey++;
551 } else if (dispmode>1 &&
552 ((t==2 && bold) || (t==22 && inv) || (t==31 && under))) {
553 writecap(t_me);
554 bold=under=inv=0;
555 } else if (dispmode>1 && t==2) {
556 writecap(t_md);
557 bold=1;
558 } else if (dispmode>1 && t==22) {
559 writecap(t_mr);
560 inv=1;
561 } else if (dispmode>1 && t==31) {
562 writecap(t_us);
563 under=1;
564 } else if (dispmode>1 && t==15) {
565 if (bold || inv || under) writecap(t_me);
566 bold=under=inv=0;
567 } else if (t==9) {
568 (*w++)=t;
569 wherex=(wherex & 0xfff8)+8;
570 } else if (t<' ' && (t!=7 || !beep)) {
571 wherex++;
572 if (inv) {
573 writecap(t_me);
574 (*w++)=(t+'@');
575 } else {
576 writecap(t_mr);
577 (*w++)=(t+'@');
578 writecap(t_me);
579 }
580 if (bold) writecap(t_md);
581 if (inv) writecap(t_mr);
582 if (under) writecap(t_us);
583 } else {
584 if (t!=7) wherex++;
585 (*w++)=t;
586 }
587 if (t==' ' || t==9) {
588 lwr=r; lww=w; lwrc=rc;
589 lwbold=bold; lwinv=inv; lwunder=under;
590 lwx=wherex;
591 }
592 }
593 if (w!=writebuf) write(1, writebuf, w-writebuf);
594}
595
596#ifdef __GNUC__
597void doprogramline(unsigned char *readbuf, int rc) {
598#else
599void doprogramline(readbuf, rc)
600unsigned char *readbuf;
601int rc; {
602#endif
603
604 unsigned char *w, *r, *r2, t;
605 if (dispmode==0) {
606 formatter(readbuf, rc);
607 return;
608 }
609 w=r=readbuf;
610 while(rc-->0) {
611 t=(*r++);
612 if (idstatus==0)
613 if (*inid=='\0') {
614 idstatus=1;
615 wpc=protcmd;
616 inid=id;
617 } else if (*inid==t && (inid!=id || r==(readbuf+1) || *(r-2)=='\n')) {
618 inid++;
619 (*wpc++)=t;
620 } else {
621 r2=protcmd;
622 while (r2!=wpc) (*w++)=(*r2++);
623 (*w++)=t;
624 wpc=protcmd;
625 inid=id;
626 }
627 if (idstatus==1)
628 if (t=='\n') {
629 *wpc='\0';
630 doprotcommand();
631 inid=id;
632 wpc=protcmd;
633 idstatus=0;
634 } else (*wpc++)=t;
635 }
636 if (w!=readbuf) formatter(readbuf, w-readbuf);
637}
638
639#ifdef __GNUC__
640void write1(unsigned char t, int pos) {
641#else
642void write1(t, pos)
643unsigned char t;
644int pos; {
645#endif
646 if (no_echo && pos>=plen) {
647 write(1, "*", 1);
648 } else if (t>=' ')
649 write(1, &t, 1);
650 else {
651 setinv();
652 t+='@';
653 write(1, &t, 1);
654 normal();
655 }
656}
657
658#ifdef __GNUC__
659void ofsredisplay(int x) {
660#else
661void ofsredisplay(x) {
662#endif
663/* redisplays starting at x */
664 unsigned char *w;
665 int i;
666 gotoxy(x, yinput);
667 if (inputlast-inputofs>=x) {
668 i=((inputlast-inputofs>cols-1 ? cols-1-x : inputlast-inputofs-x));
669 for (w=input+inputofs+x; i--; w++) write1(*w, w-input);
670 }
671 cleareol();
672 gotoxy(inputcursor, yinput);
673 cursorwhere=1;
674}
675
676#ifdef __GNUC__
677void delempty(struct histinfo *leavealone) {
678#else
679void delempty(leavealone)
680struct histinfo *leavealone; {
681#endif
682 struct histinfo *h, *h2;
683 int cont=0;
684 h=histoldest;
685 do {
686 cont=0;
687 if ((h->len<=h->plen) && (h!=leavealone)) {
688 histlines--;
689 h->next->prev=h->prev;
690 h->prev->next=h->next;
691 h2=h->prev;
692 free(h);
693 if (h==histoldest) {
694 histoldest=h2;
695 cont=1;
696 }
697 h=h2;
698 } else h=h->prev;
699 } while ((h!=histoldest || cont) && histlines>0);
700 if (!histlines) {
701 histoldest=NULL;
702 return;
703 }
704}
705
706struct histinfo *makenew() {
707 struct histinfo *nh;
708 if (!histlines) {
709 nh=(struct histinfo *)malloc(sizeof (struct histinfo));
710 nh->prev=nh->next=histoldest=nh;
711 histlines++;
712 } else if (histlines<MAX_HIST_LINES) {
713 nh=(struct histinfo *)malloc(sizeof (struct histinfo));
714 nh->prev=histoldest;
715 nh->next=histoldest->next;
716 histoldest->next=nh;
717 nh->next->prev=nh;
718 histlines++;
719 } else {
720 nh=histoldest;
721 histoldest=nh->prev;
722 }
723 return nh;
724}
725
726#ifdef __GNUC__
727void sendline(int yank) {
728#else
729void sendline(yank) {
730#endif
731 if (!specialprompt) {
732 histcurrent->len=inputlast;
733 histcurrent->plen=plen;
734 }
735 if (!yank) {
736 input[inputlast]='\n';
737 if (printmode) formatter(input, inputlast+1);
738 if (write(writefd, input+plen, inputlast+1-plen)<inputlast+1-plen)
739 cleanupexit(1, "write error");
740 }
741 input[inputlast]='\0';
742 delempty(NULL);
743 histcurrent=makenew();
744 input=histcurrent->string;
745 strcpy(input, prompt);
746 plen=strlen(prompt);
747 inputofs=specialprompt=0;
748 modified=1;
749 inputcursor=inputlast=plen;
750 ofsredisplay(0);
751 no_echo=0;
752}
753
754void modify() {
755 struct histinfo *h;
756 if (!modified) {
757 if (inputlast>plen) {
758 h=histcurrent;
759 delempty(h);
760 histcurrent=makenew();
761 strcpy(histcurrent->string, h->string);
762 input=histcurrent->string;
763 }
764 modified=1;
765 }
766}
767
768void fixpos() {
769 if (inputcursor<8 && inputofs>0) {
770 inputofs-=cols-16;
771 inputcursor+=cols-16;
772 if (inputofs<0) {
773 inputcursor+=inputofs;
774 inputofs=0;
775 }
776 ofsredisplay(0);
777 } else if (inputcursor>cols-8) {
778 inputofs+=cols-16;
779 inputcursor-=cols-16;
780 ofsredisplay(0);
781 }
782}
783
784void reshow() {
785 if (inputlast>cols-8) {
786 inputcursor=cols-9;
787 inputofs=inputlast-cols+9;
788 } else {
789 inputofs=0;
790 inputcursor=inputlast;
791 }
792 ofsredisplay(0);
793}
794
795#ifdef __GNUC__
796void inschar(unsigned char t) {
797#else
798void inschar(t)
799unsigned char t; {
800#endif
801
802 unsigned char *tmp;
803
804 if (inputlast<BUF_SIZE-4) {
805 modify();
806 if (inputofs+inputcursor==inputlast) {
807 write1(t, inputlast);
808 input[inputlast++]=t;
809 input[inputlast]='\0';
810 inputcursor++;
811 } else {
812 tmp=input+inputlast;
813 while (tmp>=input+inputofs+inputcursor)
814 *(tmp+1)=(*tmp--);
815 input[inputofs+(inputcursor++)]=t;
816 inputlast++;
817 ofsredisplay(inputcursor-1);
818 }
819 fixpos();
820 }
821}
822
823#ifdef __GNUC__
824void dokbdchar(unsigned char t) {
825#else
826void dokbdchar(t)
827unsigned char t; {
828#endif
829
830 unsigned char *tmp;
831
832 if (inarrow==1) {
833 if (t=='[' || t=='O') {
834 inarrow++;
835 return;
836 }
837 inarrow=0;
838 } else if (inarrow==2) {
839 inarrow=0;
840 if (t=='D') t=2;
841 else if (t=='C') t=6;
842 else if (t=='A') t=16;
843 else if (t=='B') t=14;
844 else return;
845 }
846 if (ctrlx && !quote) {
847 ctrlx=0;
848 t|=0x20;
849 if (dispmode>0 && ((t=='h' && !hold_mode) || t=='y')) {
850 hold_mode=1;
851 hold_lines=0;
852 if (cursorwhere!=1) fullscroll();
853 cursorwhere=2;
854 normal();
855 gotoxy(cols-4, ystatus);
856 setinv();
857 write(1, "(h)", 3);
858 normal();
859 } else if (dispmode>0 && ((t=='h' && hold_mode) || t=='n')) {
860 hold_mode=0;
861 if (cursorwhere!=1) fullscroll();
862 cursorwhere=2;
863 normal();
864 gotoxy(cols-4, ystatus);
865 setinv();
866 write(1, " ", 3);
867 normal();
868 } else if (dispmode>0 && t=='i') {
869 dispmode=3-dispmode;
870 bold=inv=under=0;
871 } else if (dispmode>0 && t=='b') {
872 beep=!beep;
873 } else if (t=='c') cleanupexit(1, "exiting");
874 return;
875 }
876 if (cutline) donl=1;
877 if (cursorwhere!=1) {
878 normal();
879 fullscroll();
880 gotoxy(inputcursor, yinput);
881 cursorwhere=1;
882 }
883 if (t==24 && !quote) {
884 ctrlx=1;
885 return;
886 } else ctrlx=0;
887 if (t==27 && !quote) {
888 inarrow=1;
889 } else if ((t==10 || t==13) && !quote) { /* return, newline */
890 sendline(0);
891 if (tablines) {
892 curtabr=oldest;
893 curtabt=oldest->next;
894 }
895 } else if (t==25 && !quote) { /* ^y */
896 if (!specialprompt) {
897 sendline(1);
898 if (tablines) {
899 curtabr=oldest;
900 curtabt=oldest->next;
901 }
902 }
903 } else if (t==21 && !quote) { /* ^u */
904 modify();
905 input[plen]='\0';
906 inputcursor=inputlast=plen;
907 inputofs=0;
908 ofsredisplay(0);
909 } else if ((t==8 || t==0x7f) && !quote) { /* ^h, ^? */
910 if (inputcursor>plen) {
911 modify();
912 tmp=input+inputcursor+inputofs;
913 while (tmp<input+inputlast)
914 *(tmp-1)=(*tmp++);
915 input[--inputlast]='\0';
916 gotoxy(--inputcursor, yinput);
917 ofsredisplay(inputcursor);
918 fixpos();
919 }
920 } else if (t==4 && !quote) { /* ^d */
921 if (inputcursor+inputofs<inputlast) {
922 modify();
923 tmp=input+inputcursor+inputofs+1;
924 while (tmp<input+inputlast)
925 *(tmp-1)=(*tmp++);
926 input[--inputlast]='\0';
927 gotoxy(inputcursor, yinput);
928 ofsredisplay(inputcursor);
929 }
930 } else if (t==11 && !quote) { /* ^k */
931 if (inputcursor+inputofs<inputlast) {
932 modify();
933 input[inputlast=inputofs+inputcursor]='\0';
934 ofsredisplay(inputcursor);
935 }
936 } else if (t==2 && !quote) { /* ^b */
937 if (inputcursor>0 && (inputcursor>plen || inputofs>0)) {
938 gotoxy(--inputcursor, yinput);
939 fixpos();
940 }
941 } else if (t==6 && !quote) { /* ^f */
942 if (inputcursor+inputofs<inputlast) {
943 gotoxy(++inputcursor, yinput);
944 fixpos();
945 }
946 } else if (t==1 && !quote) { /* ^a */
947 if (inputcursor+inputofs>plen) {
948 if (inputofs==0)
949 gotoxy((inputcursor=plen), yinput);
950 else {
951 inputofs=0;
952 inputcursor=plen;
953 ofsredisplay(0);
954 }
955 }
956 } else if (t==5 && !quote) { /* ^e */
957 if (inputcursor+inputofs<inputlast) {
958 if (inputlast-inputofs<cols-3) {
959 gotoxy((inputcursor=inputlast-inputofs), yinput);
960 } else if (inputlast>cols-8) {
961 inputcursor=cols-9;
962 inputofs=inputlast-cols+9;
963 ofsredisplay(0);
964 } else {
965 inputofs=0;
966 inputcursor=inputlast;
967 ofsredisplay(0);
968 }
969 }
970 } else if (t==12 && !quote) { /* ^l */
971 displaystatus();
972 ofsredisplay(0);
973 } else if (t==9 && !quote) { /* TAB */
974 if (tablines) {
975 modify();
976 strcpy(input+plen, curtabt->string);
977 curtabr=curtabt->prev;
978 curtabt=curtabt->next;
979 inputlast=strlen(input);
980 reshow();
981 }
982 } else if (t==18 && !quote) { /* ^r */
983 if (tablines) {
984 modify();
985 strcpy(input+plen, curtabr->string);
986 curtabt=curtabr->next;
987 curtabr=curtabr->prev;
988 inputlast=strlen(input);
989 reshow();
990 }
991 } else if (t==16 && !quote) { /* ^p */
992 if (histlines>1 && !specialprompt) {
993 histcurrent->plen=plen;
994 histcurrent->len=inputlast;
995 histcurrent=histcurrent->next;
996 plen=histcurrent->plen;
997 inputlast=histcurrent->len;
998 input=histcurrent->string;
999 modified=0;
1000 reshow();
1001 }
1002 } else if (t==14 && !quote) { /* ^n */
1003 if (histlines>1 && !specialprompt) {
1004 histcurrent->plen=plen;
1005 histcurrent->len=inputlast;
1006 histcurrent=histcurrent->prev;
1007 plen=histcurrent->plen;
1008 inputlast=histcurrent->len;
1009 input=histcurrent->string;
1010 modified=0;
1011 reshow();
1012 }
1013 } else if (t==15 &&!quote) { /* ^o */
1014 if (strlen(o_buffer)) modify();
1015 for (tmp=o_buffer; *tmp; tmp++) inschar(*tmp);
1016 } else if (t==20 && !quote) { /* ^t */
1017 write(writefd, ctrl_t, strlen(ctrl_t));
1018 } else if (t==22 && !quote) { /* ^v */
1019 quote++;
1020 return;
1021#ifdef CONTROL_W
1022 } else if (t==23 && !quote) { /* ^w */
1023 fullscroll();
1024 normal();
1025 clearscreen();
1026 bold=inv=under=wherex=wherey=donl=0;
1027 displaystatus();
1028 ofsredisplay(0);
1029#endif
1030 } else inschar(t);
1031 quote=0;
1032}
1033
1034#ifdef __GNUC__
1035void barf(unsigned char *m) {
1036#else
1037void barf(m)
1038unsigned char *m; {
1039#endif
1040 fprintf(stderr, "%s\n", m);
1041 exit(1);
1042}
1043
1044char *myname;
1045
1046void use() {
1047 fprintf(stderr, "Use: %s [options] program [program's options]\n", myname);
1048 fprintf(stderr, "Options are:\n");
1049 fprintf(stderr, " -raw, -cooked, -irc : set display mode\n");
1050 fprintf(stderr, " -print : print your input lines\n");
1051 fprintf(stderr, " -prompt <prompt> : specify a command-line prompt\n");
1052 fprintf(stderr, " -hold : pause after each full screen (for cooked/irc mode)\n");
1053 fprintf(stderr, " -beep : let beeps through (for cooked/irc mode)\n");
1054 fprintf(stderr, " -flow : leave ^S/^Q alone for flow control\n");
1055 exit(1);
1056}
1057
1058#ifdef __GNUC__
1059int main(int argc, char *argv[]) {
1060#else
1061int main(argc, argv)
1062int argc;
1063char *argv[]; {
1064#endif
1065
1066 char *vr;
1067 int pfds0[2], pfds1[2], pfds2[2];
1068
1069 myname=(*argv);
1070 prompt=nullstring;
1071 while (argc>1) {
1072 if (strcmp(argv[1], "-raw")==0) {
1073 dispmode=0;
1074 argv++; argc--;
1075 } else if (strcmp(argv[1], "-cooked")==0) {
1076 dispmode=1;
1077 argv++; argc--;
1078 } else if (strcmp(argv[1], "-irc")==0) {
1079 dispmode=2;
1080 argv++; argc--;
1081 } else if (strcmp(argv[1], "-hold")==0) {
1082 hold_mode=1;
1083 argv++; argc--;
1084 } else if (strcmp(argv[1], "-print")==0) {
1085 argv++; argc--;
1086 if (prompt==nullstring) prompt=defprompt;
1087 printmode=1;
1088 } else if (strcmp(argv[1], "-beep")==0) {
1089 beep=1;
1090 argv++; argc--;
1091 } else if (strcmp(argv[1], "-flow")==0) {
1092 flow=1;
1093 argv++; argc--;
1094 } else if (strcmp(argv[1], "-prompt")==0) {
1095 if (argc>2) prompt=(unsigned char *)argv[2];
1096 if (strlen(prompt)>8) barf("Prompt too long");
1097 argv+=2; argc-=2;
1098 } else break;
1099 }
1100 if (argc<2) use();
1101 if (!isatty(0)) barf("I can only run on a tty, sorry");
1102 if ((termtype=getenv("TERM"))==NULL) barf("No terminal type set");
1103 if (tgetent(termcap, termtype)<1) barf("No termcap info for your terminal");
1104 tc=capabilities;
1105 if ((t_cm=(char *)tgetstr("cm", &tc))==NULL)
1106 barf("Can't find a way to move the cursor around with your terminal");
1107 if ((t_cl=(char *)tgetstr("cl", &tc))==NULL)
1108 barf("Can't find a way to clear the screen with your terminal");
1109 if ((t_ce=(char *)tgetstr("ce", &tc))==NULL)
1110 barf("Can't find a way to clear to end of line with your terminal");
1111 if ((t_cs=(char *)tgetstr("cs", &tc))==NULL) {
1112 if (strncmp(termtype, "xterm", 5)==0 || strncmp(termtype, "vt100", 5)==0)
1113 ansi_cs=1;
1114 else
1115 barf("Can't find a way to set the scrolling region with your terminal");
1116 }
1117 if ((t_me=(char *)tgetstr("me", &tc))!=NULL) {
1118 if ((t_mr=(char *)tgetstr("mr", &tc))==NULL) t_mr=t_me;
1119 if ((t_md=(char *)tgetstr("md", &tc))==NULL) t_md=t_me;
1120 if ((t_us=(char *)tgetstr("us", &tc))==NULL) t_us=t_me;
1121 } else if ((t_me=(char *)tgetstr("se", &tc))!=NULL &&
1122 (t_mr=(char *)tgetstr("so", &tc))!=NULL) {
1123 t_md=t_mr;
1124 t_us=tc;
1125 (*tc++)='\0';
1126 } else {
1127 t_me=t_md=t_mr=t_us=tc;
1128 (*tc++)='\0';
1129 }
1130
1131/*
1132 if ((ttyfd=open("/dev/tty", O_RDWR))<0 &&
1133 (ttyfd=open("/dev/tty", O_RDONLY))<0) barf("Can't open terminal!");
1134 */
1135 ttyfd = 0;
1136
1137#ifdef TIOCGWINSZ
1138 if (ioctl(ttyfd, TIOCGWINSZ, &wsz)<0 || wsz.ws_row<1 || wsz.ws_col<1) {
1139#endif
1140 lines=((vr=getenv("LINES"))?atoi(vr):0);
1141 cols=((vr=getenv("COLUMNS"))?atoi(vr):0);
1142 if (lines<1 || cols<1) {
1143 if ((lines=tgetnum("li"))<1 || (cols=tgetnum("co"))<1) {
1144 lines=24; cols=80;
1145 }
1146 }
1147#ifdef TIOCGWINSZ
1148 } else {
1149 lines=wsz.ws_row;
1150 cols=wsz.ws_col;
1151 }
1152#endif
1153
1154 if (pipe(pfds0)<0 || pipe(pfds1)<0 || pipe(pfds2)<0) {
1155 perror("pipe");
1156 exit(1);
1157 }
1158 mypid=getpid();
1159 switch (pid=fork()) {
1160 case -1:
1161 perror("fork");
1162 exit(1);
1163 case 0:
1164 if (pfds0[0]!=0) dup2(pfds0[0], 0);
1165 if (pfds1[1]!=1) dup2(pfds1[1], 1);
1166 if (pfds2[1]!=2) dup2(pfds2[1], 2);
1167 if (pfds0[0]>2) close(pfds0[0]);
1168 if (pfds0[1]>2) close(pfds0[1]);
1169 if (pfds1[0]>2) close(pfds1[0]);
1170 if (pfds1[1]>2) close(pfds1[1]);
1171 if (pfds2[0]>2) close(pfds2[0]);
1172 if (pfds2[1]>2) close(pfds2[1]);
1173 /* okay we can read from 0 and write to 1 and 2, now.. it seems */
1174 execvp(argv[1], argv+1);
1175 perror("exec");
1176 sleep(1);
1177 exit(1);
1178 default:
1179 close(pfds0[0]);
1180 close(pfds1[1]);
1181 close(pfds2[1]);
1182 readfd=pfds1[0];
1183 writefd=pfds0[1];
1184 errfd=pfds2[0];
1185 }
1186
1187#ifdef USE_SGTTY
1188
1189 if (ioctl(ttyfd, TIOCGETP, &term)<0 || ioctl(ttyfd, TIOCGETC, &tch)<0 ||
1190 ioctl(ttyfd, TIOCGLTC, &lch)<0) {
1191 perror("sgtty get ioctl");
1192 exit(1);
1193 }
1194 term0=term;
1195 tch0=tch;
1196 lch0=lch;
1197 term.sg_flags|=CBREAK;
1198 term.sg_flags&= ~ECHO & ~CRMOD;
1199
1200 memset(&tch, -1, sizeof(tch));
1201 memset(&lch, -1, sizeof(lch));
1202 tch.t_intrc=(char)28;
1203 tch.t_quitc=(char)3;
1204 if (flow) {
1205 tch.t_startc=(char)17;
1206 tch.t_stopc=(char)19;
1207 }
1208 lch.t_suspc=(char)26;
1209
1210 if (ioctl(ttyfd, TIOCSETP, &term)<0 || ioctl(ttyfd, TIOCSETC, &tch)<0 ||
1211 ioctl(ttyfd, TIOCSLTC, &lch)<0) {
1212 perror("sgtty set ioctl");
1213 exit(1);
1214 }
1215
1216#else
1217 if (tcgetattr(ttyfd, &term)<0) {
1218 perror("tcgetattr");
1219 exit(1);
1220 }
1221 term0=term;
1222
1223 term.c_lflag &= ~ECHO & ~ICANON;
1224 term.c_cc[VTIME]=(char)0;
1225 term.c_cc[VMIN]=(char)1;
1226 if (!flow) {
1227 term.c_cc[VSTOP]=(char)0;
1228 term.c_cc[VSTART]=(char)0;
1229 }
1230 term.c_cc[VQUIT]=(char)3;
1231 term.c_cc[VINTR]=(char)28; /* reverse ^c and ^\ */
1232 term.c_cc[VSUSP]=(char)26;
1233#ifdef VREPRINT
1234 term.c_cc[VREPRINT]=(char)0;
1235#endif
1236#ifdef VDISCARD
1237 term.c_cc[VDISCARD]=(char)0;
1238#endif
1239#ifdef VLNEXT
1240 term.c_cc[VLNEXT]=(char)0;
1241#endif
1242#ifdef VDSUSP
1243 term.c_cc[VDSUSP]=(char)0;
1244#endif
1245
1246 if (tcsetattr(ttyfd, TCSANOW, &term)<0) {
1247 perror("tcsetattr");
1248 exit(1);
1249 }
1250#endif
1251
1252 allsigs();
1253
1254 ystatus=lines-2;
1255 yinput=lines-1;
1256
1257 if (lines>255) barf("Screen too big");
1258 if (ystatus<=2 || cols<20) barf("Screen too small");
1259
1260 statusline=(unsigned char *)malloc(MAX_COLS);
1261 writebuf=(unsigned char *)malloc(20*BUF_SIZE);
1262 strcpy(tmpstr, " ");
1263 for (i=1; i<argc; i++)
1264 if (strlen(tmpstr)+strlen(argv[i])<cols-1) {
1265 strcat(tmpstr, argv[i]);
1266 strcat(tmpstr, " ");
1267 }
1268 setstatus(tmpstr);
1269
1270 if (dispmode==0) wherey=ystatus-1;
1271 clearscreen();
1272 displaystatus();
1273
1274 histoldest=histcurrent=(struct histinfo *)malloc(sizeof (struct histinfo));
1275 input=histcurrent->string;
1276 histcurrent->prev=histcurrent->next=histcurrent;
1277 histlines=1;
1278 plen=strlen(prompt);
1279 inputlast=inputcursor=plen;
1280 strcpy(input, prompt);
1281 ofsredisplay(0);
1282 *protcmd='\0';
1283 *o_buffer='\0';
1284 cursorwhere=1;
1285
1286 FD_ZERO(&ready);
1287 FD_SET(ttyfd, &ready);
1288 FD_SET(readfd, &ready);
1289 FD_SET(errfd, &ready);
1290
1291 while(1) {
1292 result=ready;
1293 if (select(64, &result, NULL, NULL, NULL)<=0)
1294 if (errno==EINTR) continue;
1295 else cleanupexit(1, "select error");
1296
1297 if (FD_ISSET(readfd, &result))
1298 if ((rc=read(readfd, readbuf, BUF_SIZE))>0)
1299 doprogramline(readbuf, rc);
1300 else
1301 cleanupexit(1, "program terminated");
1302 if (FD_ISSET(errfd, &result))
1303 if ((rc=read(errfd, readbuf, BUF_SIZE))>0)
1304 doprogramline(readbuf, rc);
1305 else
1306 cleanupexit(1, "program terminated");
1307 if (FD_ISSET(ttyfd, &result))
1308 if ((rrc=read(0, readbuf, BUF_SIZE))>0)
1309 for (t=readbuf; rrc>0; rrc--) dokbdchar(*(t++));
1310 else
1311 cleanupexit(1, "read error from keyboard");
1312 }
1313}
1314