|
|
1.1 root 1: /* curses.c */
2:
3: /* Author:
4: * Steve Kirkendall
5: * 16820 SW Tallac Way
6: * Beaverton, OR 97006
7: * [email protected], or ...uunet!tektronix!psueea!jove!kirkenda
8: */
9:
10:
11: /* This file contains the functions & variables needed for a tiny subset of
12: * curses. The principle advantage of this version of curses is its
13: * extreme speed. Disadvantages are potentially larger code, few supported
14: * functions, limited compatibility with full curses, and only stdscr.
15: */
16:
17: #include "config.h"
18: #include "vi.h"
19:
20: #if ANY_UNIX
21: # if UNIXV
22: # include <termio.h>
23: # undef TIOCWINSZ /* we can't handle it correctly yet */
24: # else
25: # include <sgtty.h>
26: # endif
27: #endif
28:
29: #if TOS
30: # include <osbind.h>
31: #endif
32:
33: #if OSK
34: # include <sgstat.h>
35: #endif
36:
37: #include <signal.h>
38:
39: extern char *getenv();
40: static void starttcap();
41:
42: /* variables, publicly available & used in the macros */
43: short ospeed; /* speed of the tty, eg B2400 */
44: #if OSK
45: char PC_; /* Pad char */
46: char *BC; /* backspace character string */
47: #else
48: char PC; /* Pad char */
49: #endif
50: WINDOW *stdscr; /* pointer into kbuf[] */
51: WINDOW kbuf[KBSIZ]; /* a very large output buffer */
52: int LINES; /* :li#: number of rows */
53: int COLS; /* :co#: number of columns */
54: int AM; /* :am: boolean: auto margins? */
55: int PT; /* :pt: boolean: physical tabs? */
56: char *VB; /* :vb=: visible bell */
57: char *UP; /* :up=: move cursor up */
58: char *SO; /* :so=: standout start */
59: char *SE; /* :se=: standout end */
60: char *US = ""; /* :us=: underline start */
61: char *UE = ""; /* :ue=: underline end */
62: char *MD = ""; /* :md=: bold start */
63: char *ME = ""; /* :me=: bold end */
64: char *AS; /* :as=: alternate (italic) start */
65: char *AE; /* :ae=: alternate (italic) end */
66: char *CM; /* :cm=: cursor movement */
67: char *CE; /* :ce=: clear to end of line */
68: char *CD; /* :cd=: clear to end of screen */
69: char *AL; /* :al=: add a line */
70: char *DL; /* :dl=: delete a line */
71: #if OSK
72: char *SR_; /* :sr=: scroll reverse */
73: #else
74: char *SR; /* :sr=: scroll reverse */
75: #endif
76: char *KS; /* :ks=: init string for cursor */
77: char *KE; /* :ke=: restore string for cursor */
78: char *KU; /* :ku=: key sequence sent by up arrow */
79: char *KD; /* :kd=: key sequence sent by down arrow */
80: char *KL; /* :kl=: key sequence sent by left arrow */
81: char *KR; /* :kr=: key sequence sent by right arrow */
82: char *HM; /* :HM=: key sequence sent by the <Home> key */
83: char *EN; /* :EN=: key sequence sent by the <End> key */
84: char *PU; /* :PU=: key sequence sent by the <PgUp> key */
85: char *PD; /* :PD=: key sequence sent by the <PgDn> key */
86: char *IM; /* :im=: insert mode start */
87: char *IC = ""; /* :ic=: insert the following character */
88: char *EI; /* :ei=: insert mode end */
89: char *DC; /* :dc=: delete a character */
90: char *TI; /* :ti=: terminal init */ /* GB */
91: char *TE; /* :te=: terminal exit */ /* GB */
92: #ifndef NO_CURSORSHAPE
93: char *CQ = (char *)0;/* :cQ=: normal cursor */
94: char *CX = (char *)1;/* :cX=: cursor used for EX command/entry */
95: char *CV = (char *)2;/* :cV=: cursor used for VI command mode */
96: char *CI = (char *)3;/* :cI=: cursor used for VI input mode */
97: char *CR = (char *)4;/* :cR=: cursor used for VI replace mode */
98: #endif
99: char *aend = ""; /* end an attribute -- either UE or ME */
100: char ERASEKEY; /* backspace key taken from ioctl structure */
101:
102: #if ANY_UNIX
103: # if UNIXV
104: static struct termio oldtermio; /* original tty mode */
105: static struct termio newtermio; /* cbreak/noecho tty mode */
106: # else
107: static struct sgttyb oldsgttyb; /* original tty mode */
108: static struct sgttyb newsgttyb; /* cbreak/nl/noecho tty mode */
109: static int oldint; /* ^C or DEL, the "intr" character */
110: # ifdef TIOCSLTC
111: static int oldswitch; /* ^Z, the "suspend" character */
112: static int oldquote; /* ^V, the "quote next char" char */
113: # endif
114: # endif
115: #endif
116:
117: #if OSK
118: static struct sgbuf oldsgttyb; /* orginal tty mode */
119: static struct sgbuf newsgttyb; /* noecho tty mode */
120: #endif
121:
122: static char *capbuf; /* capability string buffer */
123:
124:
125: void initscr()
126: {
127: /* make sure TERM variable is set */
128: #if MSDOS
129: char *val;
130: if (! (val = getenv("TERM"))
131: || !strcmp(val, "pcbios"))
132: #else
133: if (!getenv("TERM"))
134: #endif
135: {
136: #if ANY_UNIX
137: write(2, "Environment variable TERM must be set\n", (unsigned)38);
138: exit(1);
139: #endif
140: #if OSK
141: writeln(2, "Environment variable TERM must be set\n", (unsigned)38);
142: exit(1);
143: #endif
144: #if MSDOS || TOS
145: getsize(0);
146: #endif
147: }
148: else
149: {
150: #if MSDOS
151: *o_pcbios=0;
152: #endif
153: /* start termcap stuff */
154: starttcap();
155: }
156:
157: /* create stdscr and curscr */
158: stdscr = kbuf;
159:
160: /* change the terminal mode to cbreak/noecho */
161: #if ANY_UNIX
162: # if UNIXV
163: ioctl(2, TCGETA, &oldtermio);
164: # else
165: ioctl(2, TIOCGETP, &oldsgttyb);
166: # endif
167: #endif
168:
169: #if OSK
170: _gs_opt(0, &oldsgttyb);
171: #endif
172: resume_curses(TRUE);
173: }
174:
175:
176: void endwin()
177: {
178: /* change the terminal mode back the way it was */
179: suspend_curses();
180: }
181:
182:
183: static int curses_active = FALSE;
184:
185: void suspend_curses()
186: {
187: #if ANY_UNIX && !UNIXV
188: struct tchars tbuf;
189: # ifdef TIOCSLTC
190: struct ltchars ltbuf;
191: # endif
192: #endif
193: #ifndef NO_CURSORSHAPE
194: if (has_CQ)
195: {
196: do_CQ();
197: }
198: #endif
199: if (has_TE) /* GB */
200: {
201: do_TE();
202: }
203: if (has_KE)
204: {
205: do_KE();
206: }
207: refresh();
208:
209: /* change the terminal mode back the way it was */
210: #if ANY_UNIX
211: # if UNIXV
212: ioctl(2, TCSETAW, &oldtermio);
213: # else
214: ioctl(2, TIOCSETP, &oldsgttyb);
215:
216: ioctl(2, TIOCGETC, &tbuf);
217: tbuf.t_intrc = oldint;
218: ioctl(2, TIOCSETC, &tbuf);
219:
220: # ifdef TIOCSLTC
221: ioctl(2, TIOCGLTC, <buf);
222: ltbuf.t_suspc = oldswitch;
223: ltbuf.t_lnextc = oldquote;
224: ioctl(2, TIOCSLTC, <buf);
225: # endif
226: # endif
227: #endif
228: #if OSK
229: _ss_opt(0, &oldsgttyb);
230: #endif
231: curses_active = FALSE;
232: }
233:
234: void resume_curses(quietly)
235: int quietly;
236: {
237: if (!curses_active)
238: {
239: /* change the terminal mode to cbreak/noecho */
240: #if ANY_UNIX
241: # if UNIXV
242: ospeed = (oldtermio.c_cflag & CBAUD);
243: ERASEKEY = oldtermio.c_cc[VERASE];
244: newtermio = oldtermio;
245: newtermio.c_iflag &= (IXON|IXOFF|IXANY|ISTRIP|IGNBRK);
246: newtermio.c_oflag &= ~OPOST;
247: newtermio.c_lflag &= ISIG;
248: newtermio.c_cc[VINTR] = ctrl('C'); /* always use ^C for interrupts */
249: newtermio.c_cc[VMIN] = 1;
250: newtermio.c_cc[VTIME] = 0;
251: # ifdef VSWTCH
252: newtermio.c_cc[VSWTCH] = 0;
253: # endif
254: ioctl(2, TCSETAW, &newtermio);
255: # else /* BSD or V7 or Coherent or Minix */
256: struct tchars tbuf;
257: # ifdef TIOCSLTC
258: struct ltchars ltbuf;
259: # endif
260:
261: ospeed = oldsgttyb.sg_ospeed;
262: ERASEKEY = oldsgttyb.sg_erase;
263: newsgttyb = oldsgttyb;
264: newsgttyb.sg_flags |= CBREAK;
265: newsgttyb.sg_flags &= ~(CRMOD|ECHO|XTABS);
266: ioctl(2, TIOCSETP, &newsgttyb);
267:
268: ioctl(2, TIOCGETC, &tbuf);
269: oldint = tbuf.t_intrc;
270: tbuf.t_intrc = ctrl('C'); /* always use ^C for interrupts */
271: ioctl(2, TIOCSETC, &tbuf);
272:
273: # ifdef TIOCSLTC
274: ioctl(2, TIOCGLTC, <buf);
275: oldswitch = ltbuf.t_suspc;
276: ltbuf.t_suspc = 0; /* disable ^Z for elvis */
277: oldquote = ltbuf.t_lnextc;
278: ltbuf.t_lnextc = 0; /* disable ^V for elvis */
279: ioctl(2, TIOCSLTC, <buf);
280: # endif
281:
282: # endif
283: #endif
284: #if OSK
285: newsgttyb = oldsgttyb;
286: newsgttyb.sg_echo = 0;
287: newsgttyb.sg_eofch = 0;
288: newsgttyb.sg_kbach = 0;
289: newsgttyb.sg_kbich = ctrl('C');
290: _ss_opt(0, &newsgttyb);
291: ospeed = oldsgttyb.sg_baud;
292: ERASEKEY = oldsgttyb.sg_bspch;
293: #endif
294:
295: if (has_TI) /* GB */
296: {
297: do_TI();
298: }
299: if (has_KS)
300: {
301: do_KS();
302: }
303:
304: curses_active = TRUE;
305: }
306:
307: /* If we're supposed to quit quietly, then we're done */
308: if (quietly)
309: {
310: return;
311: }
312:
313: signal(SIGINT, SIG_IGN);
314:
315: move(LINES - 1, 0);
316: do_SO();
317: qaddstr("[Press <RETURN> to continue]");
318: do_SE();
319: refresh();
320: ttyread(kbuf, 20); /* in RAW mode, so <20 is very likely */
321: if (kbuf[0] == ':')
322: {
323: mode = MODE_COLON;
324: addch('\n');
325: refresh();
326: }
327: else
328: {
329: mode = MODE_VI;
330: redraw(MARK_UNSET, FALSE);
331: }
332: exwrote = FALSE;
333:
334: #if TURBOC
335: signal(SIGINT, (void(*)()) trapint);
336: #else
337: signal(SIGINT, trapint);
338: #endif
339: }
340:
341: static void lacking(s)
342: char *s;
343: {
344: write(2, "This termcap entry lacks the :", (unsigned)30);
345: write(2, s, (unsigned)2);
346: write(2, "=: capability\n", (unsigned)14);
347: #if OSK
348: write(2, "\l", 1);
349: #endif
350: exit(1);
351: }
352:
353: static void starttcap()
354: {
355: char *str;
356: static char cbmem[800];
357: #define MUSTHAVE(T,s) if (!(T = tgetstr(s, &capbuf))) lacking(s)
358: #define MAYHAVE(T,s) if (str = tgetstr(s, &capbuf)) T = str
359: #define PAIR(T,U,sT,sU) T=tgetstr(sT,&capbuf);U=tgetstr(sU,&capbuf);if (!T||!U)T=U=""
360:
361: /* allocate memory for capbuf */
362: capbuf = cbmem;
363:
364: /* get the termcap entry */
365: switch (tgetent(kbuf, getenv("TERM")))
366: {
367: case -1:
368: write(2, "Can't read /etc/termcap\n", (unsigned)24);
369: #if OSK
370: write(2, "\l", 1);
371: #endif
372: exit(2);
373:
374: case 0:
375: write(2, "Unrecognized TERM type\n", (unsigned)23);
376: #if OSK
377: write(2, "\l", 1);
378: #endif
379: exit(3);
380: }
381:
382: /* get strings */
383: MUSTHAVE(UP, "up");
384: MAYHAVE(VB, "vb");
385: MUSTHAVE(CM, "cm");
386: PAIR(SO, SE, "so", "se");
387: PAIR(TI, TE, "ti", "te");
388: if (tgetnum("ug") <= 0)
389: {
390: PAIR(US, UE, "us", "ue");
391: PAIR(MD, ME, "md", "me");
392:
393: /* get italics, or have it default to underline */
394: PAIR(AS, AE, "as", "ae");
395: if (!*AS)
396: {
397: AS = US;
398: AE = UE;
399: }
400: }
401: MAYHAVE(AL, "al");
402: MAYHAVE(DL, "dl");
403: MUSTHAVE(CE, "ce");
404: MAYHAVE(CD, "cd");
405: #if OSK
406: MAYHAVE(SR_, "sr");
407: #else
408: MAYHAVE(SR, "sr");
409: #endif
410: PAIR(IM, EI, "im", "ei");
411: MAYHAVE(IC, "ic");
412: MAYHAVE(DC, "dc");
413:
414: /* other termcap stuff */
415: AM = tgetflag("am");
416: PT = tgetflag("pt");
417: getsize(0);
418:
419: /* Key sequences */
420: PAIR(KS, KE, "ks", "ke");
421: MAYHAVE(KU, "ku"); /* up */
422: MAYHAVE(KD, "kd"); /* down */
423: MAYHAVE(KL, "kl"); /* left */
424: MAYHAVE(KR, "kr"); /* right */
425: MAYHAVE(PU, "kP"); /* PgUp */
426: MAYHAVE(PD, "kN"); /* PgDn */
427: MAYHAVE(HM, "kh"); /* Home */
428: MAYHAVE(EN, "kH"); /* End */
429: #ifndef CRUNCH
430: if (!PU) MAYHAVE(PU, "K2"); /* "3x3 pad" names for PgUp, etc. */
431: if (!PD) MAYHAVE(PD, "K5");
432: if (!HM) MAYHAVE(HM, "K1");
433: if (!EN) MAYHAVE(EN, "K4");
434:
435: MAYHAVE(PU, "PU"); /* old XENIX names for PgUp, etc. */
436: MAYHAVE(PD, "PD"); /* (overrides others, if used.) */
437: MAYHAVE(HM, "HM");
438: MAYHAVE(EN, "EN");
439: #endif
440:
441: #ifndef NO_CURSORSHAPE
442: /* cursor shapes */
443: CQ = tgetstr("cQ", &capbuf);
444: if (has_CQ)
445: {
446: CX = tgetstr("cX", &capbuf);
447: if (!CX) CX = CQ;
448: CV = tgetstr("cV", &capbuf);
449: if (!CV) CV = CQ;
450: CI = tgetstr("cI", &capbuf);
451: if (!CI) CI = CQ;
452: CR = tgetstr("cR", &capbuf);
453: if (!CR) CR = CQ;
454: }
455: # ifndef CRUNCH
456: else
457: {
458: PAIR(CQ, CV, "ve", "vs");
459: CX = CI = CR = CQ;
460: }
461: # endif /* !CRUNCH */
462: #endif /* !NO_CURSORSHAPE */
463:
464: #undef MUSTHAVE
465: #undef MAYHAVE
466: #undef PAIR
467: }
468:
469:
470: /* This function gets the window size. It uses the TIOCGWINSZ ioctl call if
471: * your system has it, or tgetnum("li") and tgetnum("co") if it doesn't.
472: * This function is called once during initialization, and thereafter it is
473: * called whenever the SIGWINCH signal is sent to this process.
474: */
475: int getsize(signo)
476: int signo;
477: {
478: int lines;
479: int cols;
480: #ifdef TIOCGWINSZ
481: struct winsize size;
482: #endif
483:
484: #ifdef SIGWINCH
485: /* reset the signal vector */
486: signal(SIGWINCH, getsize);
487: #endif
488:
489: /* get the window size, one way or another. */
490: lines = cols = 0;
491: #ifdef TIOCGWINSZ
492: if (ioctl(2, TIOCGWINSZ, &size) >= 0)
493: {
494: lines = size.ws_row;
495: cols = size.ws_col;
496: }
497: #endif
498: if ((lines == 0 || cols == 0) && signo == 0)
499: {
500: LINES = CHECKBIOS(v_rows(), tgetnum("li"));
501: COLS = CHECKBIOS(v_cols(), tgetnum("co"));
502: }
503: if (lines >= 2 && cols >= 30)
504: {
505: LINES = lines;
506: COLS = cols;
507: }
508:
509: /* Make sure we got values that we can live with */
510: if (LINES < 2 || COLS < 30)
511: {
512: write(2, "Screen too small\n", (unsigned)17);
513: #if OSK
514: write(2, "\l", 1);
515: #endif
516: endwin();
517: exit(2);
518: }
519:
520: /* !!! copy the new values into Elvis' options */
521: {
522: extern char o_columns[], o_lines[];
523:
524: *o_columns = COLS;
525: *o_lines = LINES;
526: }
527:
528: return 0;
529: }
530:
531:
532: /* This is a function version of addch() -- it is used by tputs() */
533: int faddch(ch)
534: int ch;
535: {
536: addch(ch);
537:
538: return 0;
539: }
540:
541: /* These functions are equivelent to the macros of the same names... */
542:
543: void qaddstr(str)
544: char *str;
545: {
546: REG char *s_, *d_;
547:
548: #if MSDOS
549: if (o_pcbios[0])
550: {
551: while (*str)
552: qaddch(*str++);
553: return;
554: }
555: #endif
556: for (s_=(str), d_=stdscr; *d_++ = *s_++; )
557: {
558: }
559: stdscr = d_ - 1;
560: }
561:
562: void attrset(a)
563: int a;
564: {
565: do_aend();
566: if (a == A_BOLD)
567: {
568: do_MD();
569: aend = ME;
570: }
571: else if (a == A_UNDERLINE)
572: {
573: do_US();
574: aend = UE;
575: }
576: else if (a == A_ALTCHARSET)
577: {
578: do_AS();
579: aend = AE;
580: }
581: else
582: {
583: aend = "";
584: }
585: }
586:
587:
588: void insch(ch)
589: int ch;
590: {
591: if (has_IM)
592: do_IM();
593: do_IC();
594: qaddch(ch);
595: if (has_EI)
596: do_EI();
597: }
598:
599: #if MSDOS
600:
601: static int alarmtime;
602:
603: /* raw read - #defined to read (0, ...) on non-MSDOS.
604: * With MSDOS, am maximum of 1 byte is read.
605: * If more bytes should be read, just change the loop.
606: * The following code uses the IBM-PC-System-Timer, so probably wont't work
607: * on non-compatibles.
608: */
609: /*ARGSUSED*/
610: ttyread(buf, len)
611: char *buf;
612: int len;
613: {
614: volatile char far *biostimer;
615: char oldtime;
616: int nticks = 0;
617: int pos = 0;
618:
619: biostimer = (char far *)0x0040006cl;
620: oldtime = *biostimer;
621:
622: while (!pos && (!alarmtime || nticks<alarmtime))
623: { if (kbhit())
624: if ((buf[pos++] = getch()) == 0) /* function key */
625: buf[pos-1] = '#';
626: if (oldtime != *biostimer)
627: { nticks++;
628: oldtime = *biostimer;
629: }
630: }
631: return pos;
632: }
633:
634: alarm(time)
635: int time;
636: {
637: alarmtime = 2 * time; /* ticks are 1/18 sec. */
638: }
639: #endif
640:
641: #if TOS
642:
643: static int alarmtime;
644: static long timer;
645:
646: static gettime()
647: {
648: timer = *(long *)(0x4ba);
649: }
650:
651: /*ARGSUSED*/
652: ttyread(buf, len)
653: char *buf;
654: int len;
655: {
656: int pos=0;
657: long l;
658: long endtime;
659:
660: Supexec(gettime);
661: endtime = timer+alarmtime;
662:
663: while (!pos && (!alarmtime || timer<endtime))
664: {
665: if (Bconstat(2))
666: {
667: l = Bconin(2);
668: if ((buf[pos++]=l) == '\0')
669: {
670: buf[pos-1]='#';
671: buf[pos++]=l>>16;
672: }
673: }
674: Supexec(gettime);
675: }
676: return pos;
677: }
678:
679: alarm(time)
680: int time;
681: {
682: alarmtime = 50 * time; /* ticks are 1/200 sec. */
683: }
684:
685: ttywrite(buf, len)
686: char *buf;
687: int len;
688: {
689: while (len--)
690: Bconout(2, *buf++);
691: }
692: #endif
693:
694: #if OSK
695: ttyread(buf, len)
696: char *buf;
697: int len;
698: {
699: REG int i;
700: if ((i = _gs_rdy(0)) > 0)
701: return read(0, buf, i < len ? i : len);
702: else
703: return read(0, buf, 1);
704: }
705:
706: alarm(time)
707: int time;
708: {
709: #define TIME(secs) ((secs << 8) | 0x80000000)
710: static int alrmid;
711:
712: if (time)
713: alrmid = alm_set(SIGQUIT, TIME(time));
714: else
715: alm_delete(alrmid);
716: }
717: #endif /* OSK */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.