From: Francois Fleuret Date: Fri, 29 May 2009 15:17:01 +0000 (+0200) Subject: Added ssfe.c X-Git-Url: https://fleuret.org/cgi-bin/gitweb/gitweb.cgi?p=ircml.git;a=commitdiff_plain;h=9abe05b19f6aad12fde1b748413b491aa3f444cd Added ssfe.c --- diff --git a/ssfe.c b/ssfe.c new file mode 100644 index 0000000..b37f1dc --- /dev/null +++ b/ssfe.c @@ -0,0 +1,1314 @@ +/* An ircII-like split-screen front end + Copyright (C) 1995 Roger Espel Llima + + Started: 17 Feb 95 by orabidoo + Latest modification: 7 June 97 + + To compile: gcc ssfe.c -o ssfe -ltermcap + + If it doesn't work, try gcc ssfe.c -o ssfe -lcurses + or try cc, acc or c89 instead of gcc, or -lncurses. + + Use: ssfe [options] program arguments + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation. See the file LICENSE for details. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef USE_SGTTY +#include +#else +#include +#endif + +#include + +#ifdef _AIX +#include +#endif + +#define BUF_SIZE 512 +#define MAX_COLS 512 + +unsigned char *statusline; +int ystatus, yinput; /* line number of the status line, input line */ + +int ttyfd; +#ifdef TIOCGWINSZ +struct winsize wsz; +#endif + +#ifdef USE_SGTTY +struct sgttyb term, term0; +struct tchars tch, tch0; +struct ltchars lch, lch0; +#else +struct termios term, term0; +#endif + +int pid, mypid; +int i; +int cols, lines; +int readfd, writefd, errfd; + +unsigned char *t, *w; +unsigned char tmpstr[BUF_SIZE], extrainput[BUF_SIZE+20], readbuf[2*BUF_SIZE], + *input, *writebuf, o_buffer[BUF_SIZE]; +int bold=0, inv=0, under=0, wherex=0, wherey=0, donl=0; +int hold_mode=0, hold_lines=0, ctrlx=0, beep=0, flow=0; + +unsigned char defprompt[]="> ", + nullstring[]="", + *prompt; +int plen=0, specialprompt=0, modified=1, no_echo=0; + +#define MAX_TAB_LINES 20 +struct tabinfo { + unsigned char string[BUF_SIZE]; + struct tabinfo *prev, *next; +}; +int tablines=0; +struct tabinfo *curtabt=NULL, *curtabr=NULL, *oldest=NULL; + +#define MAX_HIST_LINES 50 +struct histinfo { + unsigned char string[BUF_SIZE+20]; + int len, plen; + struct histinfo *prev, *next; +}; +int histlines=0; +struct histinfo *histcurrent=NULL, *histoldest=NULL; + +char ctrl_t[128] = "/next\n"; + +unsigned char id[]="`#ssfe#", *inid=id, protcmd[BUF_SIZE], *wpc=protcmd; +int idstatus=0; /* 0 looking for/in the word, 1 in the arguments */ +#define ID_BACK "@ssfe@" + +int rc, rrc, inputcursor, inputlast, inputofs, inarrow=0, quote=0; +int cursorwhere; /* 0 = up, 1 = down, 2 = undef */ +int dispmode=1; /* 0=raw, 1=wordwrap, 2=process ^b^v^_ */ +int printmode=0; +int cutline=0; + +char *termtype, termcap[1024], *tc, capabilities[2048]; +char *t_cm, *t_cl, *t_mr, *t_md, *t_me, *t_cs, *t_ce, *t_us; +int ansi_cs = 0; + +fd_set ready, result; +extern int errno; + +#ifdef __GNUC__ +extern unsigned char *tgoto(unsigned char *cm, int col, int line); +#else +extern unsigned char *tgoto(); +#endif + +#ifdef __GNUC__ +int myputchar(int c) { +#else +int myputchar(c) { +#endif + unsigned char cc=(unsigned char)c; + return(write(1, &cc, 1)); +} + +#ifdef __GNUC__ +int addchar(int c) { +#else +int addchar(c) { +#endif + (*w++)=(unsigned char)c; +} + +#ifdef __GNUC__ +void putcap(unsigned char *s) { +#else +void putcap(s) +unsigned char *s; { +#endif + tputs(s, 0, myputchar); +} + +#ifdef __GNUC__ +int do_cs(int y1, int y2) { +#else +int do_cs(y1, y2) { +#endif + static char temp[16]; + if (ansi_cs) { + sprintf(temp, "\e[%d;%dr", y1, y2); + write(1, temp, strlen(temp)); + } else putcap((char *)tgoto(t_cs, y2-1, y1-1)); +} + +#ifdef __GNUC__ +void writecap(unsigned char *s) { +#else +void writecap(s) +unsigned char *s; { +#endif + tputs(s, 0, addchar); +} + +#ifdef __GNUC__ +void gotoxy(int x, int y) { +#else +void gotoxy(x, y) { +#endif +/* left upper = 0, 0 */ + putcap(tgoto(t_cm, x, y)); +} + +#define clearscreen() (putcap(t_cl)) +#define cleareol() (putcap(t_ce)) +#define fullscroll() (do_cs(0, 0)) +#define winscroll() (do_cs(1, lines-2)) +#define setbold() (putcap(t_md)) +#define setunder() (putcap(t_us)) +#define setinv() (putcap(t_mr)) +#define normal() (putcap(t_me)) + +#ifdef __GNUC__ +void ofsredisplay(int x); +void inschar(unsigned char t); +void dokbdchar(unsigned char t); +#else +void ofsredisplay(); +void inschar(); +void dokbdchar(); +#endif +void displaystatus(); + +#ifdef __GNUC__ +void cleanupexit(int n, unsigned char *error) { +#else +void cleanupexit(n, error) +int n; +unsigned char *error; { +#endif + normal(); + fullscroll(); + gotoxy(0, lines-1); + cleareol(); +#ifdef USE_SGTTY + ioctl(ttyfd, TIOCSETP, &term0); + ioctl(ttyfd, TIOCSETC, &tch0); + ioctl(ttyfd, TIOCSLTC, &lch0); +#else + tcsetattr(ttyfd, TCSADRAIN, &term0); +#endif + close(ttyfd); + if (error!=NULL) + fprintf(stderr, "%s\n", error); + exit(n); +} + +void allsigs(); + +void interrupted() { + cleanupexit(1, "interrupted"); +} + +void sigpipe() { + cleanupexit(1, "program died"); +} + +void sigcont() { + allsigs(); +#ifdef USE_SGTTY + ioctl(ttyfd, TIOCSETP, &term); + ioctl(ttyfd, TIOCSETC, &tch); + ioctl(ttyfd, TIOCSLTC, &lch); +#else + tcsetattr(ttyfd, TCSANOW, &term); +#endif + wherex=0; + wherey=ystatus-1; + displaystatus(); + ofsredisplay(0); +} + +void suspend() { + normal(); + fullscroll(); + gotoxy(0, ystatus); + cleareol(); +#ifdef USE_SGTTY + ioctl(ttyfd, TIOCSETP, &term0); + ioctl(ttyfd, TIOCSETC, &tch0); + ioctl(ttyfd, TIOCSLTC, &lch0); +#else + tcsetattr(ttyfd, TCSANOW, &term0); +#endif + kill(pid, SIGCONT); + signal(SIGTSTP, SIG_DFL); + signal(SIGCONT, sigcont); + kill(mypid, SIGTSTP); +} + +void sigwinch() { +#ifdef TIOCGWINSZ + signal(SIGWINCH, sigwinch); + if (ioctl(ttyfd, TIOCGWINSZ, &wsz)>=0 && wsz.ws_row>0 && wsz.ws_col>0) { + lines=wsz.ws_row; + cols=wsz.ws_col; + cursorwhere=2; + ystatus=lines-2; + yinput=lines-1; + wherex=0; + wherey=ystatus-1; + displaystatus(); + if (inputlast>cols-8) { + inputcursor=cols-9; + inputofs=inputlast-cols+9; + } else { + inputofs=0; + inputcursor=inputlast; + } + ofsredisplay(0); + } +#endif +} + +void allsigs() { + signal(SIGHUP, interrupted); + signal(SIGINT, interrupted); + signal(SIGQUIT, SIG_IGN); + signal(SIGPIPE, sigpipe); + signal(SIGTSTP, suspend); + signal(SIGCONT, sigcont); +#ifdef TIOCGWINSZ + signal(SIGWINCH, sigwinch); +#endif +} + +#ifdef __GNUC__ +void setstatus(unsigned char *title) { +#else +void setstatus(title) +unsigned char *title; { +#endif + unsigned char *t=title; + for (;*t;t++) if (*t<' ') (*t)+='@'; + memset(statusline, ' ', MAX_COLS-1); + memcpy(statusline, title, strlen(title)='a' && *s<='z')?(*s)-32:*s)== + ((*t>='a' && *t<='z')?(*t)-32:*t)) { + if (*s=='\0') return 1; + s++; t++; + } + return 0; +} + +#ifdef __GNUC__ +void addtab(unsigned char *line) { +#else +void addtab(line) +unsigned char *line; { +#endif + struct tabinfo *nt; + + nt=oldest; + if (tablines) do { + if (casecmp(nt->string, line)) { + strcpy(nt->string, line); + if (nt==oldest) oldest=nt->prev; + else { + nt->prev->next=nt->next; + nt->next->prev=nt->prev; + nt->prev=oldest; + nt->next=oldest->next; + oldest->next=nt; + nt->next->prev=nt; + } + curtabt=oldest->next; + curtabr=oldest; + return; + } + nt=nt->next; + } while (nt!=oldest); + + if (!tablines) { + nt=(struct tabinfo *)malloc(sizeof (struct tabinfo)); + nt->prev=nt->next=curtabt=curtabr=oldest=nt; + tablines++; + } else if (tablinesprev=oldest; + nt->next=oldest->next; + oldest->next=nt; + nt->next->prev=nt; + tablines++; + } else { + nt=oldest; + oldest=nt->prev; + } + strcpy(nt->string, line); + oldest=nt->prev; + curtabt=oldest->next; + curtabr=oldest; +} + +void doprotcommand() { + unsigned char *tmp; + + switch (protcmd[0]) { + case 'i' : dispmode=2; /* set irc mode, ack */ + bold=inv=under=0; + write(writefd, "@ssfe@i\n", 8); + break; + case 'c' : dispmode=1; /* set cooked mode, ack */ + write(writefd, "@ssfe@c\n", 8); + break; + case 's' : setstatus(protcmd+1); /* set status */ + displaystatus(); + break; + case 'T' : strncpy(ctrl_t, protcmd+1, 127); /* set ^t's text */ + ctrl_t[126] = '\0'; + strcat(ctrl_t, "\n"); + break; + case 't' : addtab(protcmd+1); /* add tabkey entry */ + break; + case 'l' : fullscroll(); /* clear screen */ + normal(); + clearscreen(); + bold=inv=under=wherex=wherey=donl=0; + displaystatus(); + ofsredisplay(0); + break; + + case 'P' : no_echo = 1; /* password prompt */ + case 'p' : if (strlen(protcmd+1)<=8) { /* prompt something */ + fullscroll(); + if (!specialprompt) { + histcurrent->len=inputlast; + histcurrent->plen=plen; + } + input=extrainput; + strcpy(input, protcmd+1); + plen=strlen(input); + inputofs=0; + modified=specialprompt=1; + inputlast=inputcursor=plen; + ofsredisplay(0); + } + break; + case 'n' : if (cursorwhere!=1) { /* type text */ + normal(); + fullscroll(); + gotoxy(inputcursor, yinput); + cursorwhere=1; + } + for (tmp=protcmd+1; *tmp; tmp++) { + inschar(*tmp); + } + break; + case 'o' : strcpy(o_buffer, protcmd+1); + break; + } +} + +void newline() { + unsigned char t; + hold_lines++; + if (hold_mode && hold_lines>lines-4) { + normal(); + fullscroll(); + gotoxy(cols-4, ystatus); + setinv(); + write(1, "(H)", 3); + while(1) { + read(0, &t, 1); + if (t==9) break; + dokbdchar(t); + } + normal(); + fullscroll(); + gotoxy(cols-4, ystatus); + setinv(); + write(1, "(h)", 3); + hold_lines=0; + normal(); + winscroll(); + gotoxy(cols-1, wherey); + if (bold) setbold(); + if (under) setunder(); + if (inv) setinv(); + } +} + +#ifdef __GNUC__ +void formatter(unsigned char *readbuf, int rc) { +#else +void formatter(readbuf, rc) +unsigned char *readbuf; +int rc; { +#endif + + unsigned char t, *r, *lwr, *lww; + int lwrc, lwbold, lwunder, lwinv, lwx; + + if (cursorwhere!=0) { + winscroll(); + gotoxy(wherex, wherey); + cursorwhere=0; + } + if (donl) { + newline(); + write(1, "\r\n", 2); + normal(); + wherex=0; + bold=inv=under=lwbold=lwinv=lwunder=0; + if (wherey1) { + if (bold) setbold(); + if (under) setunder(); + if (inv) setinv(); + lwbold=bold; + lwinv=inv; + lwunder=under; + } + if (rc && readbuf[rc-1]=='\n') { + rc--; + donl=1; cutline=0; + } else { + donl=0; + if (dispmode==0) cutline=1; + } + if (dispmode==0) { + if (rc) write(1, readbuf, rc); + normal(); + return; + } + lww=w=writebuf; + lwr=r=readbuf; + lwrc=rc; + lwx=wherex; + while(rc-->0) { + t=(*r++); + if (t=='\r') continue; + if (wherex>cols-2 || (t==9 && wherex>(cols-2)&0xfff8)) { + if (t==' ' || t==9) ; + else if (lww>writebuf+cols/2) { + wherex=lwx; r=lwr; w=lww; rc=lwrc; + bold=lwbold; inv=lwinv; under=lwunder; wherex=lwx; + } else { + rc++; r--; + } + write(1, writebuf, w-writebuf); + newline(); + write(1, "\r\n ", 13); + w=writebuf; + lwr=r; lww=w; lwrc=rc; + lwbold=bold; lwinv=inv; lwunder=under; + lwx=wherex=11; + if (wherey1 && + ((t==2 && bold) || (t==22 && inv) || (t==31 && under))) { + writecap(t_me); + bold=under=inv=0; + } else if (dispmode>1 && t==2) { + writecap(t_md); + bold=1; + } else if (dispmode>1 && t==22) { + writecap(t_mr); + inv=1; + } else if (dispmode>1 && t==31) { + writecap(t_us); + under=1; + } else if (dispmode>1 && t==15) { + if (bold || inv || under) writecap(t_me); + bold=under=inv=0; + } else if (t==9) { + (*w++)=t; + wherex=(wherex & 0xfff8)+8; + } else if (t<' ' && (t!=7 || !beep)) { + wherex++; + if (inv) { + writecap(t_me); + (*w++)=(t+'@'); + } else { + writecap(t_mr); + (*w++)=(t+'@'); + writecap(t_me); + } + if (bold) writecap(t_md); + if (inv) writecap(t_mr); + if (under) writecap(t_us); + } else { + if (t!=7) wherex++; + (*w++)=t; + } + if (t==' ' || t==9) { + lwr=r; lww=w; lwrc=rc; + lwbold=bold; lwinv=inv; lwunder=under; + lwx=wherex; + } + } + if (w!=writebuf) write(1, writebuf, w-writebuf); +} + +#ifdef __GNUC__ +void doprogramline(unsigned char *readbuf, int rc) { +#else +void doprogramline(readbuf, rc) +unsigned char *readbuf; +int rc; { +#endif + + unsigned char *w, *r, *r2, t; + if (dispmode==0) { + formatter(readbuf, rc); + return; + } + w=r=readbuf; + while(rc-->0) { + t=(*r++); + if (idstatus==0) + if (*inid=='\0') { + idstatus=1; + wpc=protcmd; + inid=id; + } else if (*inid==t && (inid!=id || r==(readbuf+1) || *(r-2)=='\n')) { + inid++; + (*wpc++)=t; + } else { + r2=protcmd; + while (r2!=wpc) (*w++)=(*r2++); + (*w++)=t; + wpc=protcmd; + inid=id; + } + if (idstatus==1) + if (t=='\n') { + *wpc='\0'; + doprotcommand(); + inid=id; + wpc=protcmd; + idstatus=0; + } else (*wpc++)=t; + } + if (w!=readbuf) formatter(readbuf, w-readbuf); +} + +#ifdef __GNUC__ +void write1(unsigned char t, int pos) { +#else +void write1(t, pos) +unsigned char t; +int pos; { +#endif + if (no_echo && pos>=plen) { + write(1, "*", 1); + } else if (t>=' ') + write(1, &t, 1); + else { + setinv(); + t+='@'; + write(1, &t, 1); + normal(); + } +} + +#ifdef __GNUC__ +void ofsredisplay(int x) { +#else +void ofsredisplay(x) { +#endif +/* redisplays starting at x */ + unsigned char *w; + int i; + gotoxy(x, yinput); + if (inputlast-inputofs>=x) { + i=((inputlast-inputofs>cols-1 ? cols-1-x : inputlast-inputofs-x)); + for (w=input+inputofs+x; i--; w++) write1(*w, w-input); + } + cleareol(); + gotoxy(inputcursor, yinput); + cursorwhere=1; +} + +#ifdef __GNUC__ +void delempty(struct histinfo *leavealone) { +#else +void delempty(leavealone) +struct histinfo *leavealone; { +#endif + struct histinfo *h, *h2; + int cont=0; + h=histoldest; + do { + cont=0; + if ((h->len<=h->plen) && (h!=leavealone)) { + histlines--; + h->next->prev=h->prev; + h->prev->next=h->next; + h2=h->prev; + free(h); + if (h==histoldest) { + histoldest=h2; + cont=1; + } + h=h2; + } else h=h->prev; + } while ((h!=histoldest || cont) && histlines>0); + if (!histlines) { + histoldest=NULL; + return; + } +} + +struct histinfo *makenew() { + struct histinfo *nh; + if (!histlines) { + nh=(struct histinfo *)malloc(sizeof (struct histinfo)); + nh->prev=nh->next=histoldest=nh; + histlines++; + } else if (histlinesprev=histoldest; + nh->next=histoldest->next; + histoldest->next=nh; + nh->next->prev=nh; + histlines++; + } else { + nh=histoldest; + histoldest=nh->prev; + } + return nh; +} + +#ifdef __GNUC__ +void sendline(int yank) { +#else +void sendline(yank) { +#endif + if (!specialprompt) { + histcurrent->len=inputlast; + histcurrent->plen=plen; + } + if (!yank) { + input[inputlast]='\n'; + if (printmode) formatter(input, inputlast+1); + if (write(writefd, input+plen, inputlast+1-plen)string; + strcpy(input, prompt); + plen=strlen(prompt); + inputofs=specialprompt=0; + modified=1; + inputcursor=inputlast=plen; + ofsredisplay(0); + no_echo=0; +} + +void modify() { + struct histinfo *h; + if (!modified) { + if (inputlast>plen) { + h=histcurrent; + delempty(h); + histcurrent=makenew(); + strcpy(histcurrent->string, h->string); + input=histcurrent->string; + } + modified=1; + } +} + +void fixpos() { + if (inputcursor<8 && inputofs>0) { + inputofs-=cols-16; + inputcursor+=cols-16; + if (inputofs<0) { + inputcursor+=inputofs; + inputofs=0; + } + ofsredisplay(0); + } else if (inputcursor>cols-8) { + inputofs+=cols-16; + inputcursor-=cols-16; + ofsredisplay(0); + } +} + +void reshow() { + if (inputlast>cols-8) { + inputcursor=cols-9; + inputofs=inputlast-cols+9; + } else { + inputofs=0; + inputcursor=inputlast; + } + ofsredisplay(0); +} + +#ifdef __GNUC__ +void inschar(unsigned char t) { +#else +void inschar(t) +unsigned char t; { +#endif + + unsigned char *tmp; + + if (inputlast=input+inputofs+inputcursor) + *(tmp+1)=(*tmp--); + input[inputofs+(inputcursor++)]=t; + inputlast++; + ofsredisplay(inputcursor-1); + } + fixpos(); + } +} + +#ifdef __GNUC__ +void dokbdchar(unsigned char t) { +#else +void dokbdchar(t) +unsigned char t; { +#endif + + unsigned char *tmp; + + if (inarrow==1) { + if (t=='[' || t=='O') { + inarrow++; + return; + } + inarrow=0; + } else if (inarrow==2) { + inarrow=0; + if (t=='D') t=2; + else if (t=='C') t=6; + else if (t=='A') t=16; + else if (t=='B') t=14; + else return; + } + if (ctrlx && !quote) { + ctrlx=0; + t|=0x20; + if (dispmode>0 && ((t=='h' && !hold_mode) || t=='y')) { + hold_mode=1; + hold_lines=0; + if (cursorwhere!=1) fullscroll(); + cursorwhere=2; + normal(); + gotoxy(cols-4, ystatus); + setinv(); + write(1, "(h)", 3); + normal(); + } else if (dispmode>0 && ((t=='h' && hold_mode) || t=='n')) { + hold_mode=0; + if (cursorwhere!=1) fullscroll(); + cursorwhere=2; + normal(); + gotoxy(cols-4, ystatus); + setinv(); + write(1, " ", 3); + normal(); + } else if (dispmode>0 && t=='i') { + dispmode=3-dispmode; + bold=inv=under=0; + } else if (dispmode>0 && t=='b') { + beep=!beep; + } else if (t=='c') cleanupexit(1, "exiting"); + return; + } + if (cutline) donl=1; + if (cursorwhere!=1) { + normal(); + fullscroll(); + gotoxy(inputcursor, yinput); + cursorwhere=1; + } + if (t==24 && !quote) { + ctrlx=1; + return; + } else ctrlx=0; + if (t==27 && !quote) { + inarrow=1; + } else if ((t==10 || t==13) && !quote) { /* return, newline */ + sendline(0); + if (tablines) { + curtabr=oldest; + curtabt=oldest->next; + } + } else if (t==25 && !quote) { /* ^y */ + if (!specialprompt) { + sendline(1); + if (tablines) { + curtabr=oldest; + curtabt=oldest->next; + } + } + } else if (t==21 && !quote) { /* ^u */ + modify(); + input[plen]='\0'; + inputcursor=inputlast=plen; + inputofs=0; + ofsredisplay(0); + } else if ((t==8 || t==0x7f) && !quote) { /* ^h, ^? */ + if (inputcursor>plen) { + modify(); + tmp=input+inputcursor+inputofs; + while (tmp0 && (inputcursor>plen || inputofs>0)) { + gotoxy(--inputcursor, yinput); + fixpos(); + } + } else if (t==6 && !quote) { /* ^f */ + if (inputcursor+inputofsplen) { + if (inputofs==0) + gotoxy((inputcursor=plen), yinput); + else { + inputofs=0; + inputcursor=plen; + ofsredisplay(0); + } + } + } else if (t==5 && !quote) { /* ^e */ + if (inputcursor+inputofscols-8) { + inputcursor=cols-9; + inputofs=inputlast-cols+9; + ofsredisplay(0); + } else { + inputofs=0; + inputcursor=inputlast; + ofsredisplay(0); + } + } + } else if (t==12 && !quote) { /* ^l */ + displaystatus(); + ofsredisplay(0); + } else if (t==9 && !quote) { /* TAB */ + if (tablines) { + modify(); + strcpy(input+plen, curtabt->string); + curtabr=curtabt->prev; + curtabt=curtabt->next; + inputlast=strlen(input); + reshow(); + } + } else if (t==18 && !quote) { /* ^r */ + if (tablines) { + modify(); + strcpy(input+plen, curtabr->string); + curtabt=curtabr->next; + curtabr=curtabr->prev; + inputlast=strlen(input); + reshow(); + } + } else if (t==16 && !quote) { /* ^p */ + if (histlines>1 && !specialprompt) { + histcurrent->plen=plen; + histcurrent->len=inputlast; + histcurrent=histcurrent->next; + plen=histcurrent->plen; + inputlast=histcurrent->len; + input=histcurrent->string; + modified=0; + reshow(); + } + } else if (t==14 && !quote) { /* ^n */ + if (histlines>1 && !specialprompt) { + histcurrent->plen=plen; + histcurrent->len=inputlast; + histcurrent=histcurrent->prev; + plen=histcurrent->plen; + inputlast=histcurrent->len; + input=histcurrent->string; + modified=0; + reshow(); + } + } else if (t==15 &&!quote) { /* ^o */ + if (strlen(o_buffer)) modify(); + for (tmp=o_buffer; *tmp; tmp++) inschar(*tmp); + } else if (t==20 && !quote) { /* ^t */ + write(writefd, ctrl_t, strlen(ctrl_t)); + } else if (t==22 && !quote) { /* ^v */ + quote++; + return; +#ifdef CONTROL_W + } else if (t==23 && !quote) { /* ^w */ + fullscroll(); + normal(); + clearscreen(); + bold=inv=under=wherex=wherey=donl=0; + displaystatus(); + ofsredisplay(0); +#endif + } else inschar(t); + quote=0; +} + +#ifdef __GNUC__ +void barf(unsigned char *m) { +#else +void barf(m) +unsigned char *m; { +#endif + fprintf(stderr, "%s\n", m); + exit(1); +} + +char *myname; + +void use() { + fprintf(stderr, "Use: %s [options] program [program's options]\n", myname); + fprintf(stderr, "Options are:\n"); + fprintf(stderr, " -raw, -cooked, -irc : set display mode\n"); + fprintf(stderr, " -print : print your input lines\n"); + fprintf(stderr, " -prompt : specify a command-line prompt\n"); + fprintf(stderr, " -hold : pause after each full screen (for cooked/irc mode)\n"); + fprintf(stderr, " -beep : let beeps through (for cooked/irc mode)\n"); + fprintf(stderr, " -flow : leave ^S/^Q alone for flow control\n"); + exit(1); +} + +#ifdef __GNUC__ +int main(int argc, char *argv[]) { +#else +int main(argc, argv) +int argc; +char *argv[]; { +#endif + + char *vr; + int pfds0[2], pfds1[2], pfds2[2]; + + myname=(*argv); + prompt=nullstring; + while (argc>1) { + if (strcmp(argv[1], "-raw")==0) { + dispmode=0; + argv++; argc--; + } else if (strcmp(argv[1], "-cooked")==0) { + dispmode=1; + argv++; argc--; + } else if (strcmp(argv[1], "-irc")==0) { + dispmode=2; + argv++; argc--; + } else if (strcmp(argv[1], "-hold")==0) { + hold_mode=1; + argv++; argc--; + } else if (strcmp(argv[1], "-print")==0) { + argv++; argc--; + if (prompt==nullstring) prompt=defprompt; + printmode=1; + } else if (strcmp(argv[1], "-beep")==0) { + beep=1; + argv++; argc--; + } else if (strcmp(argv[1], "-flow")==0) { + flow=1; + argv++; argc--; + } else if (strcmp(argv[1], "-prompt")==0) { + if (argc>2) prompt=(unsigned char *)argv[2]; + if (strlen(prompt)>8) barf("Prompt too long"); + argv+=2; argc-=2; + } else break; + } + if (argc<2) use(); + if (!isatty(0)) barf("I can only run on a tty, sorry"); + if ((termtype=getenv("TERM"))==NULL) barf("No terminal type set"); + if (tgetent(termcap, termtype)<1) barf("No termcap info for your terminal"); + tc=capabilities; + if ((t_cm=(char *)tgetstr("cm", &tc))==NULL) + barf("Can't find a way to move the cursor around with your terminal"); + if ((t_cl=(char *)tgetstr("cl", &tc))==NULL) + barf("Can't find a way to clear the screen with your terminal"); + if ((t_ce=(char *)tgetstr("ce", &tc))==NULL) + barf("Can't find a way to clear to end of line with your terminal"); + if ((t_cs=(char *)tgetstr("cs", &tc))==NULL) { + if (strncmp(termtype, "xterm", 5)==0 || strncmp(termtype, "vt100", 5)==0) + ansi_cs=1; + else + barf("Can't find a way to set the scrolling region with your terminal"); + } + if ((t_me=(char *)tgetstr("me", &tc))!=NULL) { + if ((t_mr=(char *)tgetstr("mr", &tc))==NULL) t_mr=t_me; + if ((t_md=(char *)tgetstr("md", &tc))==NULL) t_md=t_me; + if ((t_us=(char *)tgetstr("us", &tc))==NULL) t_us=t_me; + } else if ((t_me=(char *)tgetstr("se", &tc))!=NULL && + (t_mr=(char *)tgetstr("so", &tc))!=NULL) { + t_md=t_mr; + t_us=tc; + (*tc++)='\0'; + } else { + t_me=t_md=t_mr=t_us=tc; + (*tc++)='\0'; + } + +/* + if ((ttyfd=open("/dev/tty", O_RDWR))<0 && + (ttyfd=open("/dev/tty", O_RDONLY))<0) barf("Can't open terminal!"); + */ + ttyfd = 0; + +#ifdef TIOCGWINSZ + if (ioctl(ttyfd, TIOCGWINSZ, &wsz)<0 || wsz.ws_row<1 || wsz.ws_col<1) { +#endif + lines=((vr=getenv("LINES"))?atoi(vr):0); + cols=((vr=getenv("COLUMNS"))?atoi(vr):0); + if (lines<1 || cols<1) { + if ((lines=tgetnum("li"))<1 || (cols=tgetnum("co"))<1) { + lines=24; cols=80; + } + } +#ifdef TIOCGWINSZ + } else { + lines=wsz.ws_row; + cols=wsz.ws_col; + } +#endif + + if (pipe(pfds0)<0 || pipe(pfds1)<0 || pipe(pfds2)<0) { + perror("pipe"); + exit(1); + } + mypid=getpid(); + switch (pid=fork()) { + case -1: + perror("fork"); + exit(1); + case 0: + if (pfds0[0]!=0) dup2(pfds0[0], 0); + if (pfds1[1]!=1) dup2(pfds1[1], 1); + if (pfds2[1]!=2) dup2(pfds2[1], 2); + if (pfds0[0]>2) close(pfds0[0]); + if (pfds0[1]>2) close(pfds0[1]); + if (pfds1[0]>2) close(pfds1[0]); + if (pfds1[1]>2) close(pfds1[1]); + if (pfds2[0]>2) close(pfds2[0]); + if (pfds2[1]>2) close(pfds2[1]); + /* okay we can read from 0 and write to 1 and 2, now.. it seems */ + execvp(argv[1], argv+1); + perror("exec"); + sleep(1); + exit(1); + default: + close(pfds0[0]); + close(pfds1[1]); + close(pfds2[1]); + readfd=pfds1[0]; + writefd=pfds0[1]; + errfd=pfds2[0]; + } + +#ifdef USE_SGTTY + + if (ioctl(ttyfd, TIOCGETP, &term)<0 || ioctl(ttyfd, TIOCGETC, &tch)<0 || + ioctl(ttyfd, TIOCGLTC, &lch)<0) { + perror("sgtty get ioctl"); + exit(1); + } + term0=term; + tch0=tch; + lch0=lch; + term.sg_flags|=CBREAK; + term.sg_flags&= ~ECHO & ~CRMOD; + + memset(&tch, -1, sizeof(tch)); + memset(&lch, -1, sizeof(lch)); + tch.t_intrc=(char)28; + tch.t_quitc=(char)3; + if (flow) { + tch.t_startc=(char)17; + tch.t_stopc=(char)19; + } + lch.t_suspc=(char)26; + + if (ioctl(ttyfd, TIOCSETP, &term)<0 || ioctl(ttyfd, TIOCSETC, &tch)<0 || + ioctl(ttyfd, TIOCSLTC, &lch)<0) { + perror("sgtty set ioctl"); + exit(1); + } + +#else + if (tcgetattr(ttyfd, &term)<0) { + perror("tcgetattr"); + exit(1); + } + term0=term; + + term.c_lflag &= ~ECHO & ~ICANON; + term.c_cc[VTIME]=(char)0; + term.c_cc[VMIN]=(char)1; + if (!flow) { + term.c_cc[VSTOP]=(char)0; + term.c_cc[VSTART]=(char)0; + } + term.c_cc[VQUIT]=(char)3; + term.c_cc[VINTR]=(char)28; /* reverse ^c and ^\ */ + term.c_cc[VSUSP]=(char)26; +#ifdef VREPRINT + term.c_cc[VREPRINT]=(char)0; +#endif +#ifdef VDISCARD + term.c_cc[VDISCARD]=(char)0; +#endif +#ifdef VLNEXT + term.c_cc[VLNEXT]=(char)0; +#endif +#ifdef VDSUSP + term.c_cc[VDSUSP]=(char)0; +#endif + + if (tcsetattr(ttyfd, TCSANOW, &term)<0) { + perror("tcsetattr"); + exit(1); + } +#endif + + allsigs(); + + ystatus=lines-2; + yinput=lines-1; + + if (lines>255) barf("Screen too big"); + if (ystatus<=2 || cols<20) barf("Screen too small"); + + statusline=(unsigned char *)malloc(MAX_COLS); + writebuf=(unsigned char *)malloc(20*BUF_SIZE); + strcpy(tmpstr, " "); + for (i=1; istring; + histcurrent->prev=histcurrent->next=histcurrent; + histlines=1; + plen=strlen(prompt); + inputlast=inputcursor=plen; + strcpy(input, prompt); + ofsredisplay(0); + *protcmd='\0'; + *o_buffer='\0'; + cursorwhere=1; + + FD_ZERO(&ready); + FD_SET(ttyfd, &ready); + FD_SET(readfd, &ready); + FD_SET(errfd, &ready); + + while(1) { + result=ready; + if (select(64, &result, NULL, NULL, NULL)<=0) + if (errno==EINTR) continue; + else cleanupexit(1, "select error"); + + if (FD_ISSET(readfd, &result)) + if ((rc=read(readfd, readbuf, BUF_SIZE))>0) + doprogramline(readbuf, rc); + else + cleanupexit(1, "program terminated"); + if (FD_ISSET(errfd, &result)) + if ((rc=read(errfd, readbuf, BUF_SIZE))>0) + doprogramline(readbuf, rc); + else + cleanupexit(1, "program terminated"); + if (FD_ISSET(ttyfd, &result)) + if ((rrc=read(0, readbuf, BUF_SIZE))>0) + for (t=readbuf; rrc>0; rrc--) dokbdchar(*(t++)); + else + cleanupexit(1, "read error from keyboard"); + } +} +