Commit | Line | Data |
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 | |
43 | unsigned char *statusline; |
44 | int ystatus, yinput; /* line number of the status line, input line */ |
45 | |
46 | int ttyfd; |
47 | #ifdef TIOCGWINSZ |
48 | struct winsize wsz; |
49 | #endif |
50 | |
51 | #ifdef USE_SGTTY |
52 | struct sgttyb term, term0; |
53 | struct tchars tch, tch0; |
54 | struct ltchars lch, lch0; |
55 | #else |
56 | struct termios term, term0; |
57 | #endif |
58 | |
59 | int pid, mypid; |
60 | int i; |
61 | int cols, lines; |
62 | int readfd, writefd, errfd; |
63 | |
64 | unsigned char *t, *w; |
65 | unsigned char tmpstr[BUF_SIZE], extrainput[BUF_SIZE+20], readbuf[2*BUF_SIZE], |
66 | *input, *writebuf, o_buffer[BUF_SIZE]; |
67 | int bold=0, inv=0, under=0, wherex=0, wherey=0, donl=0; |
68 | int hold_mode=0, hold_lines=0, ctrlx=0, beep=0, flow=0; |
69 | |
70 | unsigned char defprompt[]="> ", |
71 | nullstring[]="", |
72 | *prompt; |
73 | int plen=0, specialprompt=0, modified=1, no_echo=0; |
74 | |
75 | #define MAX_TAB_LINES 20 |
76 | struct tabinfo { |
77 | unsigned char string[BUF_SIZE]; |
78 | struct tabinfo *prev, *next; |
79 | }; |
80 | int tablines=0; |
81 | struct tabinfo *curtabt=NULL, *curtabr=NULL, *oldest=NULL; |
82 | |
83 | #define MAX_HIST_LINES 50 |
84 | struct histinfo { |
85 | unsigned char string[BUF_SIZE+20]; |
86 | int len, plen; |
87 | struct histinfo *prev, *next; |
88 | }; |
89 | int histlines=0; |
90 | struct histinfo *histcurrent=NULL, *histoldest=NULL; |
91 | |
92 | char ctrl_t[128] = "/next\n"; |
93 | |
94 | unsigned char id[]="`#ssfe#", *inid=id, protcmd[BUF_SIZE], *wpc=protcmd; |
95 | int idstatus=0; /* 0 looking for/in the word, 1 in the arguments */ |
96 | #define ID_BACK "@ssfe@" |
97 | |
98 | int rc, rrc, inputcursor, inputlast, inputofs, inarrow=0, quote=0; |
99 | int cursorwhere; /* 0 = up, 1 = down, 2 = undef */ |
100 | int dispmode=1; /* 0=raw, 1=wordwrap, 2=process ^b^v^_ */ |
101 | int printmode=0; |
102 | int cutline=0; |
103 | |
104 | char *termtype, termcap[1024], *tc, capabilities[2048]; |
105 | char *t_cm, *t_cl, *t_mr, *t_md, *t_me, *t_cs, *t_ce, *t_us; |
106 | int ansi_cs = 0; |
107 | |
108 | fd_set ready, result; |
109 | extern int errno; |
110 | |
111 | #ifdef __GNUC__ |
112 | extern unsigned char *tgoto(unsigned char *cm, int col, int line); |
113 | #else |
114 | extern unsigned char *tgoto(); |
115 | #endif |
116 | |
117 | #ifdef __GNUC__ |
118 | int myputchar(int c) { |
119 | #else |
120 | int myputchar(c) { |
121 | #endif |
122 | unsigned char cc=(unsigned char)c; |
123 | return(write(1, &cc, 1)); |
124 | } |
125 | |
126 | #ifdef __GNUC__ |
127 | int addchar(int c) { |
128 | #else |
129 | int addchar(c) { |
130 | #endif |
131 | (*w++)=(unsigned char)c; |
132 | } |
133 | |
134 | #ifdef __GNUC__ |
135 | void putcap(unsigned char *s) { |
136 | #else |
137 | void putcap(s) |
138 | unsigned char *s; { |
139 | #endif |
140 | tputs(s, 0, myputchar); |
141 | } |
142 | |
143 | #ifdef __GNUC__ |
144 | int do_cs(int y1, int y2) { |
145 | #else |
146 | int 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__ |
156 | void writecap(unsigned char *s) { |
157 | #else |
158 | void writecap(s) |
159 | unsigned char *s; { |
160 | #endif |
161 | tputs(s, 0, addchar); |
162 | } |
163 | |
164 | #ifdef __GNUC__ |
165 | void gotoxy(int x, int y) { |
166 | #else |
167 | void 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__ |
183 | void ofsredisplay(int x); |
184 | void inschar(unsigned char t); |
185 | void dokbdchar(unsigned char t); |
186 | #else |
187 | void ofsredisplay(); |
188 | void inschar(); |
189 | void dokbdchar(); |
190 | #endif |
191 | void displaystatus(); |
192 | |
193 | #ifdef __GNUC__ |
194 | void cleanupexit(int n, unsigned char *error) { |
195 | #else |
196 | void cleanupexit(n, error) |
197 | int n; |
198 | unsigned 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 | |
217 | void allsigs(); |
218 | |
219 | void interrupted() { |
220 | cleanupexit(1, "interrupted"); |
221 | } |
222 | |
223 | void sigpipe() { |
224 | cleanupexit(1, "program died"); |
225 | } |
226 | |
227 | void 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 | |
242 | void 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 | |
260 | void 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 | |
284 | void 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__ |
297 | void setstatus(unsigned char *title) { |
298 | #else |
299 | void setstatus(title) |
300 | unsigned 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 | |
308 | void 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__ |
324 | int casecmp(unsigned char *s, unsigned char *t) { |
325 | #else |
326 | int casecmp(s, t) |
327 | unsigned 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__ |
338 | void addtab(unsigned char *line) { |
339 | #else |
340 | void addtab(line) |
341 | unsigned 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 | |
386 | void 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 | |
445 | void 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__ |
475 | void formatter(unsigned char *readbuf, int rc) { |
476 | #else |
477 | void formatter(readbuf, rc) |
478 | unsigned char *readbuf; |
479 | int 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__ |
597 | void doprogramline(unsigned char *readbuf, int rc) { |
598 | #else |
599 | void doprogramline(readbuf, rc) |
600 | unsigned char *readbuf; |
601 | int 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__ |
640 | void write1(unsigned char t, int pos) { |
641 | #else |
642 | void write1(t, pos) |
643 | unsigned char t; |
644 | int 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__ |
659 | void ofsredisplay(int x) { |
660 | #else |
661 | void 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__ |
677 | void delempty(struct histinfo *leavealone) { |
678 | #else |
679 | void delempty(leavealone) |
680 | struct 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 | |
706 | struct 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__ |
727 | void sendline(int yank) { |
728 | #else |
729 | void 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 | |
754 | void 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 | |
768 | void 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 | |
784 | void 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__ |
796 | void inschar(unsigned char t) { |
797 | #else |
798 | void inschar(t) |
799 | unsigned 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__ |
824 | void dokbdchar(unsigned char t) { |
825 | #else |
826 | void dokbdchar(t) |
827 | unsigned 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__ |
1035 | void barf(unsigned char *m) { |
1036 | #else |
1037 | void barf(m) |
1038 | unsigned char *m; { |
1039 | #endif |
1040 | fprintf(stderr, "%s\n", m); |
1041 | exit(1); |
1042 | } |
1043 | |
1044 | char *myname; |
1045 | |
1046 | void 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__ |
1059 | int main(int argc, char *argv[]) { |
1060 | #else |
1061 | int main(argc, argv) |
1062 | int argc; |
1063 | char *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 | |