1 /*
2 * ANSI.C
3 *
4 * Written by Paul Edwards et al and released to the public
5 * domain.
6 *
7 * Adapted to the peculiarities of UNIX consoles by Tobias Ernst.
8 *
9 * Screen definitions & routines using ANSI codes.
10 */
11
12 #ifndef USE_CURSES
13
14 #include <stdio.h>
15 #include <string.h>
16 #include <stdlib.h>
17 #include <ctype.h>
18
19 /* The following variables define the minimum terminal
20 size. Theoretically, the minimum terminal size should be
21 1x1. However, large parts of Msged cannot cope with small terminal
22 sizes (they will create bus errors and all such things), therefore,
23 the routines in this module always report a minimum terminal
24 size. Of course, if the terminal is smaller than this minimum size,
25 the output will be garbage, but at least the program will not crash
26 ... */
27
28 #define MINTERMX 10 /* 10 x 8 is the absolute minimum */
29 #define MINTERMY 8
30
31
32 #if defined(MSDOS) || defined(OS2) || defined(WINNT)
33 #include <conio.h>
34 #endif
35
36
37
38 #if defined(UNIX) || defined(Cygwin)
39
40 #include <termios.h> /* struct winsize */
41 #include <sys/ioctl.h> /* ioctl.h */
42 #include <stdio.h> /* fileno */
43 #include <unistd.h> /* sleep */
44 #include <signal.h> /* signal ... */
45 #include <setjmp.h> /* longjmp */
46
47 #ifdef sun
48 #include <curses.h>
49 #endif
50
51 static volatile int resize_pending = 0;
52 #if (defined(__unix__) || defined(unix)) && !defined(USG)
53 #include <sys/param.h> /* used to differentiate BSD from SYSV */
54 #endif
55
56 static struct termios oldtios;
57
58 // FILE *fDebug = stderr; // SMS 991013: does not seem to be used
59
block_console(int min,int time)60 void block_console(int min, int time)
61 {
62 struct termios tios;
63
64 /* if (min == 0 && time == 0)
65 {
66 time = 1;
67 } */
68
69 tcgetattr(0, &tios);
70 tios.c_cc[VMIN] = min;
71 tios.c_cc[VTIME] = time;
72 tcsetattr(0, TCSANOW, &tios);
73 }
74
75 #endif
76
77
78 #include "winsys.h"
79 #include "unused.h"
80
81 #if defined(UNIX) || defined(Cygwin)
82 static int waiting = -1;
83 #include "keys.h"
84
85 static unsigned meta_alphas[] =
86 {
87 Key_A_A, Key_A_B, Key_A_C, Key_A_D, Key_A_E, Key_A_F, Key_A_G,
88 Key_A_H, Key_A_I, Key_A_J, Key_A_K, Key_A_L, Key_A_M, Key_A_N,
89 Key_A_O, Key_A_P, Key_A_Q, Key_A_R, Key_A_S, Key_A_T, Key_A_U,
90 Key_A_V, Key_A_W, Key_A_X, Key_A_Y, Key_A_Z
91 };
92
93 static unsigned meta_digits[] =
94 {
95 Key_A_0, Key_A_1, Key_A_2, Key_A_3, Key_A_4,
96 Key_A_5, Key_A_6, Key_A_7, Key_A_8, Key_A_9
97 };
98 #endif
99
100 #include "readtc.h"
101
102
103 int vcol, vrow; /* cursor position */
104 int color = 7; /* current color on screen */
105 int cur_start = 0;
106 int cur_end = 0;
107 static unsigned char *allowed_special_characters = NULL;
108
109 #ifdef SASC
110 int akbhit(void);
111 int agetch(void);
112 int agetchr(void);
113 int coninit(void);
114 void confin(void);
115 #endif
116
117 #if defined(UNIX) || defined(Cygwin)
118 volatile
119 #endif
120 TERM term =
121 {
122 80,
123 #ifdef SASC
124 30,
125 #else
126 24,
127 #endif
128 0
129 };
130
131 static unsigned int *scrnbuf, *colbuf;
132
133
134 #define EBUFSZ 100
135 static EVT EVent[EBUFSZ]; /* event circular queue */
136 static int ebufin = 0; /* event in */
137 static int ebufout = 0; /* event out */
138
139 static int tcflags = 0; /* what we want to extract from termcap */
140
141 static int mykbhit(void);
142 static int FullBuffer(void);
143
144 static char *mono_colors[128]=
145 {
146 ";8", "", "", "", "", "", "","",
147 ";8", ";1", ";1", ";1", ";1", ";1", ";1", ";1",
148 ";7", ";7;8", ";7", ";7", ";7", ";7", ";7", ";7",
149 ";7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7",
150 ";7", ";7", ";7;8", ";7", ";7", ";7", ";7", ";7",
151 ";7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7",
152 ";7", ";7", ";7", ";7;8", ";7", ";7", ";7", ";7",
153 ";7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7",
154 ";7", ";7", ";7", ";7", ";7;8", ";7", ";7", ";7",
155 ";7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7",
156 ";7", ";7", ";7", ";7", ";7", ";7;8", ";7", ";7",
157 ";7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7",
158 ";7", ";7", ";7", ";7", ";7", ";7", ";7;8", ";7",
159 ";7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7",
160 ";7", ";7", ";7", ";7", ";7", ";7", ";7", ";7;8",
161 ";7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7",
162 };
163
164 static int ansi_foreground_colors[8]=
165 {
166 30, /* black */
167 34, /* blue */
168 32, /* green */
169 36, /* cyan */
170 31, /* red */
171 35, /* magenta */
172 33, /* brown (or yellow) */
173 37 /* light gray (or white) */
174 };
175
176 static int ansi_background_colors[8]=
177 {
178 40, /* black */
179 44, /* blue */
180 42, /* green */
181 46, /* cyan */
182 41, /* red */
183 45, /* magenta */
184 43, /* brown */
185 47 /* gray */
186 };
187
TTBeginOutput(void)188 void TTBeginOutput(void) {}
TTEndOutput(void)189 void TTEndOutput(void) {}
190
TTScolor(unsigned int Attr)191 int TTScolor(unsigned int Attr)
192 {
193 if (wnd_force_monochrome)
194 {
195 printf ("%c%c0%sm",0x1b,0x5b,mono_colors[Attr&0x7F]);
196 }
197 else
198 {
199 printf ("%c%c0m",0x1b,0x5b); /* reset attributes */
200
201 fputs ("\033[", stdout);
202 if (Attr & 0x08)
203 {
204 fputs ("1;", stdout); /* intensified foreground */
205 }
206 if (Attr & 0x80)
207 {
208 fputs ("5;", stdout); /* intensified background */
209 }
210 printf("%d;%dm", ansi_foreground_colors[Attr&0x7],
211 ansi_background_colors[(Attr >> 4) & 0x7]);
212 }
213 if ((Attr & F_ALTERNATE) && (!(color & F_ALTERNATE)) && tt_alternate_start)
214 {
215 fputs(tt_alternate_start, stdout);
216 }
217 else
218 if ((!(Attr & F_ALTERNATE)) && (color & F_ALTERNATE) && tt_alternate_end)
219 {
220 fputs(tt_alternate_end, stdout);
221 }
222 color = Attr;
223 return 1;
224 }
225
TTCurSet(int st)226 int TTCurSet(int st)
227 {
228 if (st && tt_showcursor)
229 {
230 fputs(tt_showcursor, stdout);
231 fflush(stdout);
232 }
233 else if (!st && tt_hidecursor)
234 {
235 fputs(tt_hidecursor, stdout);
236 fflush(stdout);
237 }
238 return 1;
239 }
240
TTgotoxy_noflush(int row,int col)241 static int TTgotoxy_noflush(int row, int col)
242 {
243 if (row >= term.NRow)
244 {
245 row = term.NRow - 1;
246 }
247 if (col >= term.NCol)
248 {
249 col = term.NCol - 1;
250 }
251 vrow = row;
252 vcol = col;
253 printf("\033[%d;%dH", row + 1 , col + 1);
254 return 1;
255 }
256
TTgotoxy(int row,int col)257 int TTgotoxy(int row, int col)
258 {
259 if (row >= term.NRow)
260 {
261 row = term.NRow - 1;
262 }
263 if (col >= term.NCol)
264 {
265 col = term.NCol - 1;
266 }
267 vrow = row;
268 vcol = col;
269 printf("\033[%d;%dH", row + 1, col + 1);
270 fflush(stdout);
271 return 1;
272 }
273
TTgetxy(int * row,int * col)274 int TTgetxy(int *row, int *col)
275 {
276 *row = vrow;
277 *col = vcol;
278 return 1;
279 }
280
TTPutChr(unsigned int Ch)281 int TTPutChr(unsigned int Ch)
282 {
283 putchar(Ch & 0xff);
284 scrnbuf[vrow * term.NCol + vcol] = (Ch & 0xffff);
285 colbuf[vrow * term.NCol + vcol] = color;
286 TTgotoxy(vrow, vcol);
287 /*
288 if (++vcol >= term.NCol)
289 {
290 vcol = 0;
291 if (++vrow >= term.NRow)
292 {
293 vrow = term.NRow - 1;
294 }
295 }*/
296 return 1;
297 }
298
TTWriteStr(unsigned long * b,int len,int row,int col)299 int TTWriteStr(unsigned long *b, int len, int row, int col)
300 {
301 int x;
302 int thiscol, oldcol = color, restorecol = 0;
303
304 TTgotoxy_noflush(row, col);
305 for (x = 0; x < len; x++)
306 {
307 if (vrow >= term.NRow || vcol + x >= term.NCol)
308 {
309 break; /* don't write out of area */
310 }
311 scrnbuf[vrow * term.NCol + vcol + x] = (*b & 0x0000ffffUL);
312 thiscol = (*b & 0xffff0000UL) >> 16;
313 colbuf[vrow * term.NCol + vcol + x] = thiscol;
314 if (thiscol != color)
315 {
316 TTScolor(thiscol);
317 restorecol = 1;
318 }
319 putchar(*b & 0xff);
320 b++;
321 }
322 if (restorecol)
323 {
324 TTScolor(oldcol);
325 }
326 TTgotoxy(row, col + x);
327 return 1;
328 }
329
TTStrWr(unsigned char * s,int row,int col,int len)330 int TTStrWr(unsigned char *s, int row, int col, int len)
331 {
332 int i;
333
334 if (len < 0)
335 len = strlen((char *)s);
336
337 if (row >= term.NRow || col >= term.NCol)
338 {
339 return 0;
340 }
341 if (col + len > term.NCol)
342 {
343 if ((len = term.NCol - col)<1)
344 {
345 return 0;
346 }
347 }
348
349 TTgotoxy_noflush(row, col);
350
351 for (i = 0 ; i < len; i++)
352 {
353 scrnbuf[vrow * term.NCol + vcol + i] = s[i];
354 colbuf[vrow * term.NCol + vcol + i] = color;
355 }
356 fputs((const char *)s, stdout);
357 TTgotoxy(row, col + len);
358 return 1;
359 }
360
TTReadStr(unsigned long * b,int len,int row,int col)361 int TTReadStr(unsigned long *b, int len, int row, int col)
362 {
363 int x;
364 if (row >= term.NRow || col >= term.NCol)
365 {
366 return 0;
367 }
368 if (col + len > term.NCol)
369 {
370 if ((len = term.NCol - col) < 1)
371 {
372 return 0;
373 }
374 }
375 for (x = 0; x < len; x++)
376 {
377 b[x] = scrnbuf[row * term.NCol + col + x];
378 b[x] |= (((unsigned long)colbuf[row * term.NCol + col + x]) << 16);
379 }
380 return 1;
381 }
382
TTScroll(int x1,int y1,int x2,int y2,int lines,int Dir)383 int TTScroll(int x1, int y1, int x2, int y2, int lines, int Dir)
384 {
385 int y, xp, x, x3, orgcolor;
386 int diff = x2 - x1 + 1;
387 char *buffer;
388
389 buffer = malloc(diff);
390 if (buffer == NULL)
391 {
392 TTkclose();
393 fprintf (stderr, "Out of memory!\n");
394 abort();
395 }
396
397 if (x1 < 0 || y1 <0 || x2 >= term.NCol || y2 >= term.NRow || lines<1)
398 {
399 free(buffer);
400 abort();
401 return 0;
402 }
403
404 if (Dir)
405 {
406 while (lines-- > 0)
407 {
408 for (y = y1; y < y2; y++)
409 {
410 for (x = x1; x < x1 + diff; x++)
411 {
412 scrnbuf[y * term.NCol + x] =
413 scrnbuf[(y + 1) * term.NCol + x];
414 colbuf[y * term.NCol + x] =
415 colbuf[(y + 1) * term.NCol + x];
416 }
417 }
418 for (x = x1; x < x1 + diff; x++)
419 {
420 scrnbuf[y2 * term.NCol + x] = ' ';
421 colbuf[y2 * term.NCol + x] = color;
422 }
423 }
424 }
425 else
426 {
427 while (lines-- > 0)
428 {
429 for (y = y2; y > y1; y--)
430 {
431 for (x = x1; x < x1 + diff; x++)
432 {
433 scrnbuf[y * term.NCol + x] =
434 scrnbuf[(y - 1) * term.NCol + x];
435 colbuf[y * term.NCol + x] =
436 colbuf[(y - 1) * term.NCol + x];
437 }
438 }
439 for (x = x1; x < x1 + diff; x++)
440 {
441 scrnbuf[y1 * term.NCol + x] = ' ';
442 colbuf[y1 * term.NCol + x] = color;
443 }
444 }
445 }
446
447 orgcolor = color;
448
449 for (y = y1; y <= y2; y++)
450 {
451 TTgotoxy_noflush(y, x1);
452 xp = x3 = x1;
453 TTScolor(colbuf[y * term.NCol + x1]);
454
455 while (x3 <= x2)
456 {
457 if (x3 < x2)
458 {
459 if (colbuf[y * term.NCol + x3 + 1] == color)
460 {
461 ++x3;
462 continue;
463 }
464 }
465
466 for (x = 0; x < x3-xp + 1; x++)
467 {
468 buffer[x] = scrnbuf[y * term.NCol + xp + x];
469 }
470
471 fwrite(buffer, x3 - xp + 1, 1, stdout);
472 if (x3 < x2)
473 {
474 TTScolor(colbuf[y * term.NCol + x3 + 1]);
475 }
476 xp = ++x3;
477 }
478 }
479
480 TTScolor(orgcolor);
481 TTgotoxy_noflush(y1, x1);
482 free(buffer);
483 fflush(stdout);
484 return 1;
485 }
486
487 static char spaces[3];
488 static int spaces_need_init = 1;
489
TTClear(int x1,int y1,int x2,int y2)490 int TTClear(int x1, int y1, int x2, int y2)
491 {
492 int x, y;
493
494 if (spaces_need_init)
495 {
496 memset(spaces, ' ', sizeof(spaces));
497 spaces_need_init = 0;
498 }
499
500
501 for (y = y1; y <= y2; y++)
502 {
503 TTgotoxy_noflush(y, x1);
504 if (x2 >= term.NCol - 1)
505 {
506 TTEeol();
507 }
508 else
509 {
510 for (x = x1; x <= x2; x += sizeof(spaces))
511 {
512 fwrite(spaces,
513 ((x + sizeof(spaces)) <= x2) ?
514 sizeof(spaces) : x2 - x + 1, 1, stdout);
515 }
516 }
517 for (x = x1; x <= x2; x++)
518 {
519 if (y < term.NRow && x < term.NCol)
520 {
521 scrnbuf[y * term.NCol + x] = ' ';
522 colbuf[y * term.NCol + x] = color;
523 }
524 }
525 }
526 TTgotoxy(y1, x1);
527 return 1;
528 }
529
TTEeol(void)530 int TTEeol(void)
531 {
532 int x,tnc = term.NCol;
533
534 /* The ANSI escape sequence ESC [ K does not clear the background
535 color on some terminals (ex.: Mac OS X "Terminal" application).
536 For those terminals, we write spaces instead of using this ANSI sequence.
537 */
538
539
540 if (spaces_need_init)
541 {
542 memset(spaces, ' ', sizeof(spaces));
543 spaces_need_init = 0;
544 }
545
546 if (vrow == term.NRow - 1)
547 {
548 /* Special treatment for last row to prevent scrolling when
549 writing to the character in the right bottom corner */
550
551 tnc--;
552 }
553
554 for (x = vcol; x < tnc; x += sizeof(spaces))
555 {
556 fwrite(spaces,
557 (((x + sizeof(spaces)) < tnc) ? sizeof(spaces)
558 : (tnc - x)), 1, stdout);
559 }
560
561 if (vrow == term.NRow - 1)
562 {
563 /* The very last character in the right bottom corner is
564 cleared with the ESC sequence even though that one does not
565 reliably clear the background color, because we have no
566 other way to prevent scrolling in some other, terminals,
567 like cygwin or the FreeBSD console. */
568
569 fputs("\033[0K", stdout);
570 }
571 fflush(stdout);
572
573 return 1;
574 }
575
TTdelay(int mil)576 int TTdelay(int mil)
577 {
578 unused(mil);
579 return 0;
580 }
581
582 static void TTRepaint();
583
getkey()584 int getkey()
585 {
586 #ifdef sun
587 return getch();
588 #else
589 return getchar();
590 #endif
591 }
592
TTGetKey(void)593 unsigned int TTGetKey(void)
594 {
595 int ch;
596
597 skip:
598 #if defined(OS2) || (defined(WINNT) && !defined(Cygwin))
599 ch = getch();
600 #elif defined(UNIX) || defined(Cygwin)
601 if (waiting != -1)
602 {
603 ch = waiting;
604 waiting = -1;
605 }
606 else
607 {
608 block_console(1,0);
609 ch = getkey();
610 block_console(0,0);
611 }
612 #elif defined(SASC)
613 ch = agetchr();
614 #else
615 ch = getkey();
616 #endif
617
618 #if defined(UNIX) || defined(Cygwin)
619 if (ch >= 127) /* Treat special characters */
620 {
621 int assume_meta_key = 1;
622
623 /* if the character has not been explicitly */
624 /* enabled by the user, we check if it is a */
625 /* Meta keystroke. */
626
627 if (allowed_special_characters != NULL)
628 {
629 if (strchr((const char *)allowed_special_characters, ch) != NULL)
630 {
631 assume_meta_key = 0;
632 }
633 }
634
635 if (assume_meta_key)
636 {
637 if (ch == 127)
638 {
639 if (wnd_bs_127)
640 {
641 ch = Key_BS;
642 }
643 else
644 {
645 ch = Key_Del;
646 }
647 }
648 else if (isalpha(ch - 128))
649 {
650 ch = meta_alphas[tolower(ch - 128) - 'a'];
651 }
652 else if (isdigit(ch - 128))
653 {
654 ch = meta_digits[ch - 128 - '0'];
655 }
656 }
657 }
658 else if (ch == 12)
659 {
660 TTRepaint();
661 goto skip;
662 }
663 else if (ch == 0x1b) /* interprete VT100 escape sequences */
664 {
665 block_console(0,2);
666 ch = getkey();
667 block_console(0,0);
668
669 if (ch == EOF)
670 {
671 clearerr(stdin);
672 }
673 if (ch <= 0)
674 {
675 ch = 0x1b;
676 }
677 else
678 {
679 switch (ch)
680 {
681 case 0x1B: /* double escape */
682 ch = Key_Esc;
683 break;
684 case ':':
685 ch = Key_F1;
686 break;
687 case ';':
688 ch = Key_F2;
689 break;
690 case '<':
691 ch = Key_F3;
692 break;
693 case '=':
694 ch = Key_F4;
695 break;
696 case '>':
697 ch = Key_F5;
698 break;
699 case '?':
700 ch = Key_F6;
701 break;
702 case '@':
703 ch = Key_F7;
704 break;
705 case 'A':
706 ch = Key_F8;
707 break;
708 case 'B':
709 ch = Key_F9;
710 break;
711 case 'C':
712 ch = Key_F10;
713 break;
714 case 'a':
715 ch = Key_A_A;
716 break;
717 case 'b':
718 ch = Key_A_B;
719 break;
720 case 'c':
721 ch = Key_A_C;
722 break;
723 case 'd':
724 ch = Key_A_D;
725 break;
726 case 'e':
727 ch = Key_A_E;
728 break;
729 case 'f':
730 ch = Key_A_F;
731 break;
732 case 'g':
733 ch = Key_A_G;
734 break;
735 case 'h':
736 ch = Key_A_H;
737 break;
738 case 'i':
739 ch = Key_A_I;
740 break;
741 case 'j':
742 ch = Key_A_J;
743 break;
744 case 'k':
745 ch = Key_A_K;
746 break;
747 case 'l':
748 ch = Key_A_L;
749 break;
750 case 'm':
751 ch = Key_A_M;
752 break;
753 case 'n':
754 ch = Key_A_N;
755 break;
756 case 'o':
757 ch = Key_A_O;
758 break;
759 case 'p':
760 ch = Key_A_P;
761 break;
762 case 'q':
763 ch = Key_A_Q;
764 break;
765 case 'r':
766 ch = Key_A_R;
767 break;
768 case 's':
769 ch = Key_A_S;
770 break;
771 case 't':
772 ch = Key_A_T;
773 break;
774 case 'u':
775 ch = Key_A_U;
776 break;
777 case 'v':
778 ch = Key_A_V;
779 break;
780 case 'w':
781 ch = Key_A_W;
782 break;
783 case 'x':
784 ch = Key_A_X;
785 break;
786 case 'y':
787 ch = Key_A_Y;
788 break;
789 case 'z':
790 ch = Key_A_Z;
791 break;
792 case 72:
793 ch = Key_Up;
794 break;
795 case 80:
796 ch = Key_Dwn;
797 break;
798 case 73:
799 ch = Key_PgUp;
800 break;
801 case 81:
802 ch = Key_PgDn;
803 break;
804 case 71:
805 ch = Key_Home;
806 break;
807 case 83:
808 ch = Key_Del;
809 break;
810 case 75:
811 ch = Key_Lft;
812 break;
813 case 77:
814 ch = Key_Rgt;
815 break;
816 case 'O': /* VT100 and ANSI Alt- and Function keys */
817 block_console(0,2);
818 ch = getkey();
819 block_console(0,0);
820 switch(ch)
821 {
822 case 33:
823 ch = Key_A_A;
824 break;
825 case 34:
826 ch = Key_A_R;
827 break;
828 case 35:
829 ch = Key_A_C;
830 break;
831 case 36:
832 ch = Key_A_D;
833 break;
834 case 37:
835 ch = Key_A_E;
836 break;
837 case 38:
838 ch = Key_A_G;
839 break;
840 case 39:
841 ch = Key_A_V;
842 break;
843 case 40:
844 ch = Key_A_I;
845 break;
846 case 41:
847 ch = Key_A_J;
848 break;
849 case 42:
850 ch = Key_A_H;
851 break;
852 case 43:
853 ch = Key_A_L;
854 break;
855 case 44:
856 ch = Key_A_W;
857 break;
858 case 46:
859 ch = Key_A_Y;
860 break;
861 case 48:
862 ch = Key_A_0;
863 break;
864 case 49:
865 ch = Key_A_1;
866 break;
867 case 50:
868 ch = Key_A_2;
869 break;
870 case 51:
871 ch = Key_A_3;
872 break;
873 case 52:
874 ch = Key_A_4;
875 break;
876 case 53:
877 ch = Key_A_5;
878 break;
879 case 54:
880 ch = Key_A_6;
881 break;
882 case 55:
883 ch = Key_A_7;
884 break;
885 case 56:
886 ch = Key_A_8;
887 break;
888 case 57:
889 ch = Key_A_9;
890 break;
891 case 58:
892 ch = Key_A_U;
893 break;
894 case 59:
895 ch = Key_A_T;
896 break;
897 case 60:
898 ch = Key_A_X;
899 break;
900 case 62:
901 ch = Key_A_Z;
902 break;
903 case 64:
904 ch = Key_A_B;
905 break;
906 case 65:
907 ch = Key_Up; /* Windows NT Telnet */
908 break;
909 case 66:
910 ch = Key_Dwn;
911 break;
912 case 67:
913 ch = Key_Rgt;
914 break;
915 case 68:
916 ch = Key_Lft;
917 break;
918 case 69:
919 ch = Key_A_F5;
920 break;
921 case 70:
922 ch = Key_A_F6;
923 break;
924 case 71:
925 ch = Key_A_F7;
926 break;
927 case 72:
928 ch = Key_A_F8;
929 break;
930 case 73:
931 ch = Key_A_F9;
932 break;
933 case 74:
934 ch = Key_A_F10;
935 break;
936 case 75:
937 ch = Key_A_F1;
938 break;
939 case 76:
940 ch = Key_A_F2;
941 break;
942 case 78:
943 ch = Key_A_F4;
944 break;
945 case 79:
946 ch = Key_A_F3;
947 break;
948 case 80:
949 ch = Key_F1;
950 break;
951 case 81:
952 ch = Key_F2;
953 break;
954 case 82:
955 ch = Key_F3;
956 break;
957 case 83:
958 ch = Key_F4;
959 break;
960 case 84:
961 ch = Key_F5;
962 break;
963 case 91:
964 ch = Key_A_M;
965 break;
966 case 92:
967 ch = Key_A_Q;
968 break;
969 case 93:
970 ch = Key_A_O;
971 break;
972 case 94:
973 ch = Key_A_F;
974 break;
975 case 95:
976 ch = Key_A_K;
977 break;
978 case 97:
979 ch = Key_C_F1;
980 break;
981 case 98:
982 ch = Key_C_F2;
983 break;
984 case 99:
985 ch = Key_C_F3;
986 break;
987 case 100:
988 ch = Key_C_F4;
989 break;
990 case 101:
991 ch = Key_C_F5;
992 break;
993 case 102:
994 ch = Key_C_F6;
995 break;
996 case 103:
997 ch = Key_C_F7;
998 break;
999 case 104:
1000 ch = Key_C_F8;
1001 break;
1002 case 105:
1003 ch = Key_C_F9;
1004 break;
1005 case 106:
1006 ch = Key_C_F10;
1007 break;
1008 case 110:
1009 ch = Key_Del;
1010 break;
1011 case 112:
1012 ch = Key_Ins;
1013 break;
1014 case 113:
1015 ch = Key_End;
1016 break;
1017 case 115:
1018 ch = Key_PgDn;
1019 break;
1020 case 119:
1021 ch = Key_Home;
1022 break;
1023 case 121:
1024 ch = Key_PgUp;
1025 break;
1026 case 124:
1027 ch = Key_A_S;
1028 break;
1029 case 125:
1030 ch = Key_A_P;
1031 break;
1032 case 132:
1033 ch = Key_A_N;
1034 break;
1035
1036 default:
1037 ch = 0x1B;
1038 break;
1039 }
1040 break;
1041 case '[': /* "ansi" cursor key codes */
1042 block_console(0,2);
1043 ch = getkey();
1044 block_console(0,0);
1045 switch (ch)
1046 {
1047 case 'A':
1048 ch = Key_Up;
1049 break;
1050 case 'B':
1051 ch = Key_Dwn;
1052 break;
1053 case 'C':
1054 ch = Key_Rgt;
1055 break;
1056 case 'D':
1057 ch = Key_Lft;
1058 break;
1059 case 'F':
1060 ch = Key_End;
1061 break;
1062 case 'G':
1063 ch = Key_PgDn;
1064 break;
1065 case 'H':
1066 ch = Key_Home;
1067 break;
1068 case 'I':
1069 ch = Key_PgUp;
1070 break;
1071 case 'L':
1072 ch = Key_Ins;
1073 break;
1074 case 'M':
1075 ch = Key_F1;
1076 break;
1077 case 'N':
1078 ch = Key_F2;
1079 break;
1080 case 'O':
1081 ch = Key_F3;
1082 break;
1083 case 'P':
1084 ch = Key_F4;
1085 break;
1086 case 'Q':
1087 ch = Key_F5;
1088 break;
1089 case 'R':
1090 ch = Key_F6;
1091 break;
1092 case 'S':
1093 ch = Key_F7;
1094 break;
1095 case 'T':
1096 ch = Key_F8;
1097 break;
1098 case 'U':
1099 ch = Key_F9;
1100 break;
1101 case 'V':
1102 ch = Key_F10;
1103 break;
1104 case '[': /* linux console F1 .. F5 */
1105 block_console(0,2);
1106 ch = getkey();
1107 block_console(0,0);
1108 switch(ch)
1109 {
1110 case 'A':
1111 ch = Key_F1;
1112 break;
1113 case 'B':
1114 ch = Key_F2;
1115 break;
1116 case 'C':
1117 ch = Key_F3;
1118 break;
1119 case 'D':
1120 ch = Key_F4;
1121 break;
1122 case 'E':
1123 ch = Key_F5;
1124 break;
1125 default:
1126 goto skip;
1127 }
1128 break;
1129 case '1':
1130 block_console(0,2);
1131 ch = getkey();
1132 block_console(0,0);
1133 switch (ch)
1134 {
1135 case '~':
1136 ch = Key_Home; /* xterm Home ... */
1137 break;
1138 case 53:
1139 block_console(0,2);
1140 ch = getkey();
1141 block_console(0,0);
1142 switch (ch)
1143 {
1144 case '~':
1145 ch = Key_F5; /* xterm F5 */
1146 break;
1147 default:
1148 goto skip;
1149 }
1150 break;
1151 case 55:
1152 block_console(0,2);
1153 ch = getkey();
1154 block_console(0,0);
1155 switch (ch)
1156 {
1157 case '~':
1158 ch = Key_F6; /* xterm / ANSI F6 */
1159 break;
1160 default:
1161 goto skip;
1162 }
1163 break;
1164 case 56:
1165 block_console(0,2);
1166 ch = getkey();
1167 block_console(0,0);
1168 switch (ch)
1169 {
1170 case '~':
1171 ch = Key_F7; /* xterm / ANSI F7 */
1172 break;
1173 default:
1174 goto skip;
1175 }
1176 break;
1177 case 57:
1178 block_console(0,2);
1179 ch = getkey();
1180 block_console(0,0);
1181 switch (ch)
1182 {
1183 case '~':
1184 ch = Key_F8; /* xterm / ANSI F8 */
1185 break;
1186 default:
1187 goto skip;
1188 }
1189 break;
1190 default:
1191 goto skip;
1192 }
1193 break;
1194 case '2':
1195 block_console(0,2);
1196 ch = getkey();
1197 block_console(0,0);
1198 switch (ch)
1199 {
1200 case '~':
1201 ch = Key_Ins; /* xterm Insert ... */
1202 break;
1203 case 48:
1204 block_console(0,2);
1205 ch = getkey();
1206 block_console(0,0);
1207 switch (ch)
1208 {
1209 case '~':
1210 ch = Key_F9; /* ansi/xterm F9 */
1211 break;
1212 default:
1213 goto skip;
1214 }
1215 break;
1216 case 49:
1217 block_console(0,2);
1218 ch = getkey();
1219 block_console(0,0);
1220 switch (ch)
1221 {
1222 case '~':
1223 ch = Key_F10; /* ansi/xterm F10 */
1224 break;
1225 default:
1226 goto skip;
1227 }
1228 break;
1229 default:
1230 goto skip;
1231 }
1232 break;
1233 case '3':
1234 block_console(0,2);
1235 ch = getkey();
1236 block_console(0,0);
1237 switch (ch)
1238 {
1239 case '~':
1240 ch = Key_Del; /* xterm Delete ... */
1241 break;
1242 default:
1243 goto skip;
1244 }
1245 break;
1246 case '4':
1247 block_console(0,2);
1248 ch = getkey();
1249 block_console(0,0);
1250 switch (ch)
1251 {
1252 case '~':
1253 ch = Key_End; /* xterm End ... */
1254 break;
1255 default:
1256 goto skip;
1257 }
1258 break;
1259 case '5':
1260 block_console(0,2);
1261 ch = getkey();
1262 block_console(0,0);
1263 switch (ch)
1264 {
1265 case '~':
1266 ch = Key_PgUp; /* xterm PgUp ... */
1267 break;
1268 default:
1269 goto skip;
1270 }
1271 break;
1272 case '6':
1273 block_console(0,5);
1274 ch = getkey();
1275 block_console(0,0);
1276 switch (ch)
1277 {
1278 case '~':
1279 ch = Key_PgDn; /* xterm PgDn ... */
1280 break;
1281 default:
1282 goto skip;
1283 }
1284 break;
1285 case '7':
1286 block_console(0,2);
1287 ch = getkey();
1288 block_console(0,0);
1289 switch (ch)
1290 {
1291 case '~':
1292 ch = Key_Home; /* rxvt Home ... */
1293 break;
1294 default:
1295 goto skip;
1296 }
1297 break;
1298 case '8':
1299 block_console(0,2);
1300 ch = getkey();
1301 block_console(0,0);
1302 switch (ch)
1303 {
1304 case '~':
1305 ch = Key_End; /* rxvt End ... */
1306 break;
1307 default:
1308 goto skip;
1309 }
1310 break;
1311 case EOF:
1312 clearerr(stdin);
1313 ch = 0x1b;
1314 waiting = '[';
1315 break;
1316 default:
1317 ch = 0x1b;
1318 break;
1319 }
1320 break;
1321 default:
1322 goto skip;
1323 }
1324 }
1325 }
1326 #endif
1327
1328 if (ch == '\n')
1329 {
1330 ch = '\r';
1331 }
1332 return ch;
1333 }
1334
TTSendMsg(unsigned int msg,int x,int y,unsigned int msgtype)1335 void TTSendMsg(unsigned int msg, int x, int y, unsigned int msgtype)
1336 {
1337 if (((ebufin + 1) % EBUFSZ) != ebufout)
1338 {
1339 EVent[ebufin].msg = msg;
1340 EVent[ebufin].x = x;
1341 EVent[ebufin].y = y;
1342 EVent[ebufin].msgtype = msgtype;
1343 ebufin = (ebufin + 1) % EBUFSZ;
1344 }
1345 }
1346
1347
1348 static volatile int jump_on_resize = 0;
1349 static jmp_buf jmpbuf;
1350
collect_events(int block)1351 static void collect_events(int block)
1352 {
1353 int msg;
1354
1355 #if defined(UNIX) || defined(Cygwin)
1356 while (block)
1357 {
1358 if (setjmp(jmpbuf))
1359 {
1360 block_console(0, 0);
1361 while (mykbhit()) waiting = -1;
1362 }
1363 if (waiting != -1) break;
1364 if (resize_pending != 0) break;
1365
1366 block_console (1, 0);
1367 jump_on_resize = 1;
1368 waiting = getkey();
1369 jump_on_resize = 0;
1370 if (waiting == EOF)
1371 {
1372 waiting = -1;
1373 clearerr(stdin);
1374 }
1375 }
1376 block_console (0, 0);
1377
1378 if (resize_pending != 0)
1379 {
1380 TTSendMsg(resize_pending, 0, 0, WND_WM_RESIZE);
1381 resize_pending = 0;
1382 }
1383 #endif
1384 if (mykbhit()
1385 #if ((!defined(UNIX)) && (!defined(Cygwin)))
1386 || block
1387 #endif
1388 )
1389 {
1390 msg = TTGetKey();
1391 TTSendMsg(msg, 0, 0, WND_WM_CHAR);
1392 }
1393
1394 }
1395
1396 #if defined(UNIX) || defined(Cygwin)
sigwinch_handler(int sig)1397 void sigwinch_handler(int sig)
1398 {
1399 int newcol, newrow, i, x, y;
1400 struct winsize w;
1401 unsigned int *newbuf, *oldbuf;
1402
1403 ioctl(fileno(stderr), TIOCGWINSZ, &w);
1404 newcol = w.ws_col; newrow = w.ws_row;
1405 if (newcol < MINTERMX) newcol = MINTERMX;
1406 if (newrow < MINTERMY) newrow = MINTERMY;
1407
1408 for (i = 0; i <= 1; i++)
1409 {
1410 /* +3 to provide buffer for incorrect calls to the
1411 Win... routines if the window is very small */
1412 newbuf = malloc((newcol + 3) * (newrow + 3) * sizeof(unsigned));
1413 oldbuf = i ? scrnbuf : colbuf;
1414
1415 if (newbuf == NULL)
1416 {
1417 TTkclose();
1418 abort();
1419 }
1420
1421 for (y = 0; y < newrow; y++)
1422 {
1423 for (x = 0; x < newcol; x++)
1424 {
1425 if (x >= term.NCol || y >= term.NRow)
1426 {
1427 newbuf[y * newcol + x] = i ? ' ' : 0;
1428 }
1429 else
1430 {
1431 newbuf[y * newcol + x] = oldbuf[y * term.NCol + x];
1432 }
1433 }
1434 }
1435 if (i)
1436 {
1437 free(scrnbuf);
1438 scrnbuf = newbuf;
1439 }
1440 else
1441 {
1442 free(colbuf);
1443 colbuf = newbuf;
1444 }
1445
1446 }
1447 term.NCol = newcol;
1448 term.NRow = newrow;
1449 TTRepaint();
1450
1451 resize_pending = 1;
1452
1453 #ifndef BSD /* need to reinstall the handler */
1454 signal (sig, sigwinch_handler);
1455 #endif
1456
1457 if (jump_on_resize)
1458 {
1459 jump_on_resize = 0;
1460 longjmp(jmpbuf, 1);
1461 }
1462 }
1463 #endif
1464
TTkopen(void)1465 int TTkopen(void)
1466 {
1467 int x;
1468
1469 #if defined(UNIX) || defined(Cygwin)
1470 struct termios tios;
1471 struct winsize w;
1472
1473 #if 1
1474 ioctl(fileno(stderr), TIOCGWINSZ, &w);
1475
1476 if (w.ws_row > MINTERMY)
1477 term.NRow = w.ws_row;
1478 if (w.ws_col > MINTERMY)
1479 term.NCol = w.ws_col;
1480 #endif
1481 #endif
1482
1483 if (term.NRow < MINTERMY) term.NRow = MINTERMY;
1484 if (term.NCol < MINTERMX) term.NCol = MINTERMX;
1485
1486 #ifdef SASC
1487 coninit();
1488 #endif
1489
1490 #if defined(UNIX) || defined(Cygwin)
1491 tcgetattr(0, &tios);
1492 oldtios = tios;
1493 tios.c_lflag &= ~(ICANON | ISIG);
1494 tios.c_lflag &= ~ECHO;
1495 tcsetattr(0, TCSANOW, &tios);
1496 block_console(0,0);
1497 setbuf(stdin, NULL);
1498 #ifdef sun
1499 initscr(); /* curses initialization */
1500 cbreak();
1501 noecho();
1502 #endif
1503
1504 #endif
1505 /* +3 to provide buffer for incorrect calls to the
1506 Win... routines if the window is very small */
1507 scrnbuf = malloc((term.NRow + 3) * (term.NCol + 3) * sizeof(unsigned));
1508 colbuf = malloc((term.NRow + 3) * (term.NCol + 3) * sizeof(unsigned));
1509 if (scrnbuf == NULL || colbuf == NULL)
1510 {
1511 TTkclose();
1512 fprintf (stderr, "Out of memory!\n");
1513 abort();
1514 }
1515
1516 for (x = 0; x < term.NRow * term.NCol; x++)
1517 {
1518 scrnbuf[x] = ' ';
1519 colbuf[x] = 11;
1520 }
1521
1522 #if 1
1523 #if defined(UNIX) || defined(Cygwin)
1524 signal (SIGWINCH, sigwinch_handler);
1525 #endif
1526 #endif
1527
1528 #if defined(UNIX) || defined(Cygwin)
1529 query_termcap(tcflags);
1530 #endif
1531
1532 return 0;
1533 }
1534
TTRepaint(void)1535 static void TTRepaint(void)
1536 {
1537 int x,y, xp, yp, oldcol, col, c;
1538
1539 xp = vcol; yp = vrow; oldcol = col = color;
1540 TTgotoxy_noflush(0,0);
1541 fputs("\033[2J", stdout);
1542
1543 for (y = 0; y < term.NRow; y++)
1544 {
1545 for (x = 0; x < term.NCol; x++)
1546 {
1547 if (colbuf[y * term.NCol + x] != col)
1548 {
1549 TTScolor(col = colbuf[y * term.NCol + x]);
1550 }
1551 if (x != term.NCol -1 || y != term.NRow -1)
1552 {
1553 c = scrnbuf[y * term.NCol + x];
1554 putchar(c);
1555 }
1556 else
1557 {
1558 fputs("\033[K", stdout);
1559 }
1560 }
1561 }
1562
1563 TTgotoxy(yp, xp);
1564 TTScolor(oldcol);
1565 fflush(stdout);
1566 }
1567
TTkclose(void)1568 int TTkclose(void)
1569 {
1570 TTScolor(0x07);
1571 #ifdef SASC
1572 confin();
1573 fputs("\033[31m", stdout);
1574 #else
1575 fputs("\033[0m\033[1;1H\033[J", stdout);
1576 #endif
1577 #if defined(UNIX) || defined(Cygwin)
1578 signal (SIGWINCH, SIG_DFL);
1579 tcsetattr(0, TCSANOW, &oldtios);
1580 #endif
1581 fflush(stdout);
1582 if (scrnbuf != NULL)
1583 {
1584 free(scrnbuf); scrnbuf = NULL;
1585 }
1586 if (colbuf != NULL)
1587 {
1588 free(colbuf); colbuf = NULL;
1589 }
1590 /* if (allowed_special_characters != NULL)
1591 {
1592 free(allowed_special_characters);
1593 allowed_special_characters = NULL;
1594 }
1595 we don't free this list, so that it is available in case the
1596 calling program should call TTclose and then TTopen in sequence
1597 (e.g. when it does a DOS shell)
1598 */
1599 return 0;
1600 }
1601
MouseOFF(void)1602 void MouseOFF(void)
1603 {
1604 }
1605
MouseON(void)1606 void MouseON(void)
1607 {
1608 }
1609
MouseInit(void)1610 void MouseInit(void)
1611 {
1612 }
1613
GetMouInfo(int * x,int * y)1614 int GetMouInfo(int *x, int *y)
1615 {
1616 unused(x);
1617 unused(y);
1618 return 0;
1619 }
1620
TTGetMsg(EVT * e)1621 int TTGetMsg(EVT * e)
1622 {
1623 while (ebufin == ebufout)
1624 {
1625 collect_events(1);
1626 }
1627 e->msg = EVent[ebufout].msg;
1628 e->x = EVent[ebufout].x;
1629 e->y = EVent[ebufout].y;
1630 e->msgtype = EVent[ebufout].msgtype;
1631 e->id = 0;
1632 ebufout = (ebufout + 1) % EBUFSZ;
1633 return e->msg;
1634 }
1635
TTPeekQue(void)1636 int TTPeekQue(void)
1637 {
1638 collect_events(0);
1639 return ebufin != ebufout;
1640 }
1641
TTClearQue(void)1642 void TTClearQue(void)
1643 {
1644 ebufin = ebufout;
1645 }
1646
TTGetChr(void)1647 int TTGetChr(void)
1648 {
1649 EVT e;
1650 TTGetMsg(&e);
1651 return e.msg;
1652 }
1653
TTopen(void)1654 int TTopen(void)
1655 {
1656 vcol = vrow = 0;
1657 color = 0x07;
1658 TTkopen();
1659 return 1;
1660 }
1661
TTclose(void)1662 int TTclose(void)
1663 {
1664 TTkclose();
1665 return 1;
1666 }
1667
1668
1669 /*
1670 * Configure the terminal. Configuration is retained even after TTclose.
1671 *
1672 * The ANSI/VT100 terminal accepts the following configuration keywords:
1673 *
1674 * keyword possible values
1675 *
1676 * highascii A string of high ascii bytes that, if read from the key-
1677 * board shall be reported verbatim to the calling application,
1678 * instead of being interpreted as combination of the Meta key
1679 * with a low ASCII key. You will need to enable high ascii
1680 * alphabet characters (like umlauts or cyrillics) with this.
1681 * An empty string is the deafault.
1682 *
1683 * highascii Either "1" or "0". If 1, the termcap database is queried
1684 * to see if there is pseudographics support (as, ac and ae
1685 * entires), and if so , it is enabled. If 0, pseudographics
1686 * is always disabled. "0" is the default.
1687 */
1688
TTconfigure(const char * keyword,const char * value)1689 int TTconfigure(const char *keyword, const char *value)
1690 {
1691 size_t l;
1692
1693 if (!strcmp(keyword,"highascii"))
1694 {
1695 if (allowed_special_characters != NULL)
1696 {
1697 free(allowed_special_characters);
1698 }
1699 allowed_special_characters =
1700 (unsigned char *) malloc(l = (strlen(value) + 1));
1701 memcpy(allowed_special_characters, value, l);
1702 }
1703 else if (!strcmp(keyword,"pseudographics"))
1704 {
1705 if (atoi(value))
1706 {
1707 tcflags |= QUERY_ALTCHARSET;
1708 }
1709 else
1710 {
1711 tcflags &= ~QUERY_ALTCHARSET;
1712 }
1713 query_termcap(tcflags);
1714 }
1715 else
1716 {
1717 return 0;
1718 }
1719 return 1;
1720 }
1721
1722
mykbhit(void)1723 static int mykbhit(void)
1724 {
1725 int ret;
1726
1727 if (FullBuffer())
1728 {
1729 return 0;
1730 }
1731
1732 #ifdef SASC
1733 ret = akbhit();
1734 #elif defined(UNIX) || defined(Cygwin)
1735
1736
1737 if (waiting == -1)
1738 {
1739 waiting = getkey();
1740
1741 if (waiting == EOF)
1742 {
1743 waiting = -1;
1744 clearerr(stdin);
1745 }
1746 }
1747 ret = (waiting != -1);
1748 #else
1749 ret = kbhit();
1750 #endif
1751 return ret;
1752 }
1753
dv_running(void)1754 int dv_running(void)
1755 {
1756 return 0;
1757 }
1758
FullBuffer(void)1759 static int FullBuffer(void)
1760 {
1761 if (((ebufin + 1) % EBUFSZ) != ebufout)
1762 {
1763 return 0;
1764 }
1765 else
1766 {
1767 return 1;
1768 }
1769 }
1770
1771 #endif
1772