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