/* * ANSI.C * * Written by Paul Edwards et al and released to the public * domain. * * Adapted to the peculiarities of UNIX consoles by Tobias Ernst. * * Screen definitions & routines using ANSI codes. */ #ifndef USE_CURSES #include #include #include #include /* The following variables define the minimum terminal size. Theoretically, the minimum terminal size should be 1x1. However, large parts of Msged cannot cope with small terminal sizes (they will create bus errors and all such things), therefore, the routines in this module always report a minimum terminal size. Of course, if the terminal is smaller than this minimum size, the output will be garbage, but at least the program will not crash ... */ #define MINTERMX 10 /* 10 x 8 is the absolute minimum */ #define MINTERMY 8 #if defined(MSDOS) || defined(OS2) || defined(WINNT) #include #endif #ifdef UNIX #include /* struct winsize */ #include /* ioctl.h */ #include /* fileno */ #include /* sleep */ #include /* signal ... */ #include /* longjmp */ #ifdef sun #include #endif static volatile int resize_pending = 0; #if (defined(__unix__) || defined(unix)) && !defined(USG) #include /* used to differentiate BSD from SYSV */ #endif static struct termios oldtios; // FILE *fDebug = stderr; // SMS 991013: does not seem to be used void block_console(int min, int time) { struct termios tios; /* if (min == 0 && time == 0) { time = 1; } */ tcgetattr(0, &tios); tios.c_cc[VMIN] = min; tios.c_cc[VTIME] = time; tcsetattr(0, TCSANOW, &tios); } #endif #include "winsys.h" #include "unused.h" #ifdef UNIX static int waiting = -1; #include "keys.h" static unsigned meta_alphas[] = { Key_A_A, Key_A_B, Key_A_C, Key_A_D, Key_A_E, Key_A_F, Key_A_G, Key_A_H, Key_A_I, Key_A_J, Key_A_K, Key_A_L, Key_A_M, Key_A_N, Key_A_O, Key_A_P, Key_A_Q, Key_A_R, Key_A_S, Key_A_T, Key_A_U, Key_A_V, Key_A_W, Key_A_X, Key_A_Y, Key_A_Z }; static unsigned meta_digits[] = { Key_A_0, Key_A_1, Key_A_2, Key_A_3, Key_A_4, Key_A_5, Key_A_6, Key_A_7, Key_A_8, Key_A_9 }; #endif #include "readtc.h" int vcol, vrow; /* cursor position */ int color = 7; /* current color on screen */ int cur_start = 0; int cur_end = 0; static unsigned char *allowed_special_characters = NULL; #ifdef SASC int akbhit(void); int agetch(void); int agetchr(void); int coninit(void); void confin(void); #endif #ifdef UNIX volatile #endif TERM term = { 80, #ifdef SASC 30, #else 24, #endif 0 }; static unsigned int *scrnbuf, *colbuf; #define EBUFSZ 100 static EVT EVent[EBUFSZ]; /* event circular queue */ static int ebufin = 0; /* event in */ static int ebufout = 0; /* event out */ static int tcflags = 0; /* what we want to extract from termcap */ static int mykbhit(void); static int FullBuffer(void); static char *mono_colors[128]= { ";8", "", "", "", "", "", "","", ";8", ";1", ";1", ";1", ";1", ";1", ";1", ";1", ";7", ";7;8", ";7", ";7", ";7", ";7", ";7", ";7", ";7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";7", ";7", ";7;8", ";7", ";7", ";7", ";7", ";7", ";7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";7", ";7", ";7", ";7;8", ";7", ";7", ";7", ";7", ";7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";7", ";7", ";7", ";7", ";7;8", ";7", ";7", ";7", ";7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";7", ";7", ";7", ";7", ";7", ";7;8", ";7", ";7", ";7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";7", ";7", ";7", ";7", ";7", ";7", ";7;8", ";7", ";7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";7", ";7", ";7", ";7", ";7", ";7", ";7", ";7;8", ";7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", ";1;7", }; static int ansi_foreground_colors[8]= { 30, /* black */ 34, /* blue */ 32, /* green */ 36, /* cyan */ 31, /* red */ 35, /* magenta */ 33, /* brown (or yellow) */ 37 /* light gray (or white) */ }; static int ansi_background_colors[8]= { 40, /* black */ 44, /* blue */ 42, /* green */ 46, /* cyan */ 41, /* red */ 45, /* magenta */ 43, /* brown */ 47 /* gray */ }; void TTBeginOutput(void) {} void TTEndOutput(void) {} int TTScolor(unsigned int Attr) { if (wnd_force_monochrome) { printf ("%c%c0%sm",0x1b,0x5b,mono_colors[Attr&0x7F]); } else { printf ("%c%c0m",0x1b,0x5b); /* reset attributes */ fputs ("\033[", stdout); if (Attr & 0x08) { fputs ("1;", stdout); /* intensified foreground */ } if (Attr & 0x80) { fputs ("5;", stdout); /* intensified background */ } printf("%d;%dm", ansi_foreground_colors[Attr&0x7], ansi_background_colors[(Attr >> 4) & 0x7]); } if ((Attr & F_ALTERNATE) && (!(color & F_ALTERNATE)) && tt_alternate_start) { fputs(tt_alternate_start, stdout); } else if ((!(Attr & F_ALTERNATE)) && (color & F_ALTERNATE) && tt_alternate_end) { fputs(tt_alternate_end, stdout); } color = Attr; return 1; } int TTCurSet(int st) { if (st && tt_showcursor) { fputs(tt_showcursor, stdout); fflush(stdout); } else if (!st && tt_hidecursor) { fputs(tt_hidecursor, stdout); fflush(stdout); } return 1; } static int TTgotoxy_noflush(int row, int col) { if (row >= term.NRow) { row = term.NRow - 1; } if (col >= term.NCol) { col = term.NCol - 1; } vrow = row; vcol = col; printf("\033[%d;%dH", row + 1 , col + 1); return 1; } int TTgotoxy(int row, int col) { if (row >= term.NRow) { row = term.NRow - 1; } if (col >= term.NCol) { col = term.NCol - 1; } vrow = row; vcol = col; printf("\033[%d;%dH", row + 1, col + 1); fflush(stdout); return 1; } int TTgetxy(int *row, int *col) { *row = vrow; *col = vcol; return 1; } int TTPutChr(unsigned int Ch) { putchar(Ch & 0xff); scrnbuf[vrow * term.NCol + vcol] = (Ch & 0xffff); colbuf[vrow * term.NCol + vcol] = color; TTgotoxy(vrow, vcol); /* if (++vcol >= term.NCol) { vcol = 0; if (++vrow >= term.NRow) { vrow = term.NRow - 1; } }*/ return 1; } int TTWriteStr(unsigned long *b, int len, int row, int col) { int x; int thiscol, oldcol = color, restorecol = 0; TTgotoxy_noflush(row, col); for (x = 0; x < len; x++) { if (vrow >= term.NRow || vcol + x >= term.NCol) { break; /* don't write out of area */ } scrnbuf[vrow * term.NCol + vcol + x] = (*b & 0x0000ffffUL); thiscol = (*b & 0xffff0000UL) >> 16; colbuf[vrow * term.NCol + vcol + x] = thiscol; if (thiscol != color) { TTScolor(thiscol); restorecol = 1; } putchar(*b & 0xff); b++; } if (restorecol) { TTScolor(oldcol); } TTgotoxy(row, col + x); return 1; } int TTStrWr(unsigned char *s, int row, int col, int len) { int i; if (len < 0) len = strlen((char *)s); if (row >= term.NRow || col >= term.NCol) { return 0; } if (col + len > term.NCol) { if ((len = term.NCol - col)<1) { return 0; } } TTgotoxy_noflush(row, col); for (i = 0 ; i < len; i++) { scrnbuf[vrow * term.NCol + vcol + i] = s[i]; colbuf[vrow * term.NCol + vcol + i] = color; } fputs((const char *)s, stdout); TTgotoxy(row, col + len); return 1; } int TTReadStr(unsigned long *b, int len, int row, int col) { int x; if (row >= term.NRow || col >= term.NCol) { return 0; } if (col + len > term.NCol) { if ((len = term.NCol - col) < 1) { return 0; } } for (x = 0; x < len; x++) { b[x] = scrnbuf[row * term.NCol + col + x]; b[x] |= (((unsigned long)colbuf[row * term.NCol + col + x]) << 16); } return 1; } int TTScroll(int x1, int y1, int x2, int y2, int lines, int Dir) { int y, xp, x, x3, orgcolor; int diff = x2 - x1 + 1; char *buffer; buffer = malloc(diff); if (buffer == NULL) { TTkclose(); fprintf (stderr, "Out of memory!\n"); abort(); } if (x1 < 0 || y1 <0 || x2 >= term.NCol || y2 >= term.NRow || lines<1) { free(buffer); abort(); return 0; } if (Dir) { while (lines-- > 0) { for (y = y1; y < y2; y++) { for (x = x1; x < x1 + diff; x++) { scrnbuf[y * term.NCol + x] = scrnbuf[(y + 1) * term.NCol + x]; colbuf[y * term.NCol + x] = colbuf[(y + 1) * term.NCol + x]; } } for (x = x1; x < x1 + diff; x++) { scrnbuf[y2 * term.NCol + x] = ' '; colbuf[y2 * term.NCol + x] = color; } } } else { while (lines-- > 0) { for (y = y2; y > y1; y--) { for (x = x1; x < x1 + diff; x++) { scrnbuf[y * term.NCol + x] = scrnbuf[(y - 1) * term.NCol + x]; colbuf[y * term.NCol + x] = colbuf[(y - 1) * term.NCol + x]; } } for (x = x1; x < x1 + diff; x++) { scrnbuf[y1 * term.NCol + x] = ' '; colbuf[y1 * term.NCol + x] = color; } } } orgcolor = color; for (y = y1; y <= y2; y++) { TTgotoxy_noflush(y, x1); xp = x3 = x1; TTScolor(colbuf[y * term.NCol + x1]); while (x3 <= x2) { if (x3 < x2) { if (colbuf[y * term.NCol + x3 + 1] == color) { ++x3; continue; } } for (x = 0; x < x3-xp + 1; x++) { buffer[x] = scrnbuf[y * term.NCol + xp + x]; } fwrite(buffer, x3 - xp + 1, 1, stdout); if (x3 < x2) { TTScolor(colbuf[y * term.NCol + x3 + 1]); } xp = ++x3; } } TTScolor(orgcolor); TTgotoxy_noflush(y1, x1); free(buffer); fflush(stdout); return 1; } static char spaces[3]; static int spaces_need_init = 1; int TTClear(int x1, int y1, int x2, int y2) { int x, y; if (spaces_need_init) { memset(spaces, ' ', sizeof(spaces)); spaces_need_init = 0; } for (y = y1; y <= y2; y++) { TTgotoxy_noflush(y, x1); if (x2 >= term.NCol - 1) { TTEeol(); } else { for (x = x1; x <= x2; x += sizeof(spaces)) { fwrite(spaces, ((x + sizeof(spaces)) <= x2) ? sizeof(spaces) : x2 - x + 1, 1, stdout); } } for (x = x1; x <= x2; x++) { if (y < term.NRow && x < term.NCol) { scrnbuf[y * term.NCol + x] = ' '; colbuf[y * term.NCol + x] = color; } } } TTgotoxy(y1, x1); return 1; } int TTEeol(void) { int x,tnc = term.NCol; /* The ANSI escape sequence ESC [ K does not clear the background color on some terminals (ex.: Mac OS X "Terminal" application). For those terminals, we write spaces instead of using this ANSI sequence. */ if (spaces_need_init) { memset(spaces, ' ', sizeof(spaces)); spaces_need_init = 0; } if (vrow == term.NRow - 1) { /* Special treatment for last row to prevent scrolling when writing to the character in the right bottom corner */ tnc--; } for (x = vcol; x < tnc; x += sizeof(spaces)) { fwrite(spaces, (((x + sizeof(spaces)) < tnc) ? sizeof(spaces) : (tnc - x)), 1, stdout); } if (vrow == term.NRow - 1) { /* The very last character in the right bottom corner is cleared with the ESC sequence even though that one does not reliably clear the background color, because we have no other way to prevent scrolling in some other, terminals, like cygwin or the FreeBSD console. */ fputs("\033[0K", stdout); } fflush(stdout); return 1; } int TTdelay(int mil) { unused(mil); return 0; } static void TTRepaint(); int getkey() { #ifdef sun return getch(); #else return getchar(); #endif } unsigned int TTGetKey(void) { int ch; skip: #if defined(OS2) || defined(WINNT) ch = getch(); #elif defined(UNIX) if (waiting != -1) { ch = waiting; waiting = -1; } else { block_console(1,0); ch = getkey(); block_console(0,0); } #elif defined(SASC) ch = agetchr(); #else ch = getkey(); #endif #ifdef UNIX if (ch >= 127) /* Treat special characters */ { int assume_meta_key = 1; /* if the character has not been explicitly */ /* enabled by the user, we check if it is a */ /* Meta keystroke. */ if (allowed_special_characters != NULL) { if (strchr((const char *)allowed_special_characters, ch) != NULL) { assume_meta_key = 0; } } if (assume_meta_key) { if (ch == 127) { if (wnd_bs_127) { ch = Key_BS; } else { ch = Key_Del; } } else if (isalpha(ch - 128)) { ch = meta_alphas[tolower(ch - 128) - 'a']; } else if (isdigit(ch - 128)) { ch = meta_digits[ch - 128 - '0']; } } } else if (ch == 12) { TTRepaint(); goto skip; } else if (ch == 0x1b) /* interprete VT100 escape sequences */ { block_console(0,2); ch = getkey(); block_console(0,0); if (ch == EOF) { clearerr(stdin); } if (ch <= 0) { ch = 0x1b; } else { switch (ch) { case 0x1B: /* double escape */ ch = Key_Esc; break; case ':': ch = Key_F1; break; case ';': ch = Key_F2; break; case '<': ch = Key_F3; break; case '=': ch = Key_F4; break; case '>': ch = Key_F5; break; case '?': ch = Key_F6; break; case '@': ch = Key_F7; break; case 'A': ch = Key_F8; break; case 'B': ch = Key_F9; break; case 'C': ch = Key_F10; break; case 'a': ch = Key_A_A; break; case 'b': ch = Key_A_B; break; case 'c': ch = Key_A_C; break; case 'd': ch = Key_A_D; break; case 'e': ch = Key_A_E; break; case 'f': ch = Key_A_F; break; case 'g': ch = Key_A_G; break; case 'h': ch = Key_A_H; break; case 'i': ch = Key_A_I; break; case 'j': ch = Key_A_J; break; case 'k': ch = Key_A_K; break; case 'l': ch = Key_A_L; break; case 'm': ch = Key_A_M; break; case 'n': ch = Key_A_N; break; case 'o': ch = Key_A_O; break; case 'p': ch = Key_A_P; break; case 'q': ch = Key_A_Q; break; case 'r': ch = Key_A_R; break; case 's': ch = Key_A_S; break; case 't': ch = Key_A_T; break; case 'u': ch = Key_A_U; break; case 'v': ch = Key_A_V; break; case 'w': ch = Key_A_W; break; case 'x': ch = Key_A_X; break; case 'y': ch = Key_A_Y; break; case 'z': ch = Key_A_Z; break; case 72: ch = Key_Up; break; case 80: ch = Key_Dwn; break; case 73: ch = Key_PgUp; break; case 81: ch = Key_PgDn; break; case 71: ch = Key_Home; break; case 83: ch = Key_Del; break; case 75: ch = Key_Lft; break; case 77: ch = Key_Rgt; break; case 'O': /* VT100 and ANSI Alt- and Function keys */ block_console(0,2); ch = getkey(); block_console(0,0); switch(ch) { case 33: ch = Key_A_A; break; case 34: ch = Key_A_R; break; case 35: ch = Key_A_C; break; case 36: ch = Key_A_D; break; case 37: ch = Key_A_E; break; case 38: ch = Key_A_G; break; case 39: ch = Key_A_V; break; case 40: ch = Key_A_I; break; case 41: ch = Key_A_J; break; case 42: ch = Key_A_H; break; case 43: ch = Key_A_L; break; case 44: ch = Key_A_W; break; case 46: ch = Key_A_Y; break; case 48: ch = Key_A_0; break; case 49: ch = Key_A_1; break; case 50: ch = Key_A_2; break; case 51: ch = Key_A_3; break; case 52: ch = Key_A_4; break; case 53: ch = Key_A_5; break; case 54: ch = Key_A_6; break; case 55: ch = Key_A_7; break; case 56: ch = Key_A_8; break; case 57: ch = Key_A_9; break; case 58: ch = Key_A_U; break; case 59: ch = Key_A_T; break; case 60: ch = Key_A_X; break; case 62: ch = Key_A_Z; break; case 64: ch = Key_A_B; break; case 65: ch = Key_Up; /* Windows NT Telnet */ break; case 66: ch = Key_Dwn; break; case 67: ch = Key_Rgt; break; case 68: ch = Key_Lft; break; case 69: ch = Key_A_F5; break; case 70: ch = Key_A_F6; break; case 71: ch = Key_A_F7; break; case 72: ch = Key_A_F8; break; case 73: ch = Key_A_F9; break; case 74: ch = Key_A_F10; break; case 75: ch = Key_A_F1; break; case 76: ch = Key_A_F2; break; case 78: ch = Key_A_F4; break; case 79: ch = Key_A_F3; break; case 80: ch = Key_F1; break; case 81: ch = Key_F2; break; case 82: ch = Key_F3; break; case 83: ch = Key_F4; break; case 84: ch = Key_F5; break; case 91: ch = Key_A_M; break; case 92: ch = Key_A_Q; break; case 93: ch = Key_A_O; break; case 94: ch = Key_A_F; break; case 95: ch = Key_A_K; break; case 97: ch = Key_C_F1; break; case 98: ch = Key_C_F2; break; case 99: ch = Key_C_F3; break; case 100: ch = Key_C_F4; break; case 101: ch = Key_C_F5; break; case 102: ch = Key_C_F6; break; case 103: ch = Key_C_F7; break; case 104: ch = Key_C_F8; break; case 105: ch = Key_C_F9; break; case 106: ch = Key_C_F10; break; case 110: ch = Key_Del; break; case 112: ch = Key_Ins; break; case 113: ch = Key_End; break; case 115: ch = Key_PgDn; break; case 119: ch = Key_Home; break; case 121: ch = Key_PgUp; break; case 124: ch = Key_A_S; break; case 125: ch = Key_A_P; break; case 132: ch = Key_A_N; break; default: ch = 0x1B; break; } break; case '[': /* "ansi" cursor key codes */ block_console(0,2); ch = getkey(); block_console(0,0); switch (ch) { case 'A': ch = Key_Up; break; case 'B': ch = Key_Dwn; break; case 'C': ch = Key_Rgt; break; case 'D': ch = Key_Lft; break; case 'F': ch = Key_End; break; case 'G': ch = Key_PgDn; break; case 'H': ch = Key_Home; break; case 'I': ch = Key_PgUp; break; case 'L': ch = Key_Ins; break; case 'M': ch = Key_F1; break; case 'N': ch = Key_F2; break; case 'O': ch = Key_F3; break; case 'P': ch = Key_F4; break; case 'Q': ch = Key_F5; break; case 'R': ch = Key_F6; break; case 'S': ch = Key_F7; break; case 'T': ch = Key_F8; break; case 'U': ch = Key_F9; break; case 'V': ch = Key_F10; break; case '[': /* linux console F1 .. F5 */ block_console(0,2); ch = getkey(); block_console(0,0); switch(ch) { case 'A': ch = Key_F1; break; case 'B': ch = Key_F2; break; case 'C': ch = Key_F3; break; case 'D': ch = Key_F4; break; case 'E': ch = Key_F5; break; default: goto skip; } break; case '1': block_console(0,2); ch = getkey(); block_console(0,0); switch (ch) { case '~': ch = Key_Home; /* xterm Home ... */ break; case 53: block_console(0,2); ch = getkey(); block_console(0,0); switch (ch) { case '~': ch = Key_F5; /* xterm F5 */ break; default: goto skip; } break; case 55: block_console(0,2); ch = getkey(); block_console(0,0); switch (ch) { case '~': ch = Key_F6; /* xterm / ANSI F6 */ break; default: goto skip; } break; case 56: block_console(0,2); ch = getkey(); block_console(0,0); switch (ch) { case '~': ch = Key_F7; /* xterm / ANSI F7 */ break; default: goto skip; } break; case 57: block_console(0,2); ch = getkey(); block_console(0,0); switch (ch) { case '~': ch = Key_F8; /* xterm / ANSI F8 */ break; default: goto skip; } break; default: goto skip; } break; case '2': block_console(0,2); ch = getkey(); block_console(0,0); switch (ch) { case '~': ch = Key_Ins; /* xterm Insert ... */ break; case 48: block_console(0,2); ch = getkey(); block_console(0,0); switch (ch) { case '~': ch = Key_F9; /* ansi/xterm F9 */ break; default: goto skip; } break; case 49: block_console(0,2); ch = getkey(); block_console(0,0); switch (ch) { case '~': ch = Key_F10; /* ansi/xterm F10 */ break; default: goto skip; } break; default: goto skip; } break; case '3': block_console(0,2); ch = getkey(); block_console(0,0); switch (ch) { case '~': ch = Key_Del; /* xterm Delete ... */ break; default: goto skip; } break; case '4': block_console(0,2); ch = getkey(); block_console(0,0); switch (ch) { case '~': ch = Key_End; /* xterm End ... */ break; default: goto skip; } break; case '5': block_console(0,2); ch = getkey(); block_console(0,0); switch (ch) { case '~': ch = Key_PgUp; /* xterm PgUp ... */ break; default: goto skip; } break; case '6': block_console(0,5); ch = getkey(); block_console(0,0); switch (ch) { case '~': ch = Key_PgDn; /* xterm PgDn ... */ break; default: goto skip; } break; case '7': block_console(0,2); ch = getkey(); block_console(0,0); switch (ch) { case '~': ch = Key_Home; /* rxvt Home ... */ break; default: goto skip; } break; case '8': block_console(0,2); ch = getkey(); block_console(0,0); switch (ch) { case '~': ch = Key_End; /* rxvt End ... */ break; default: goto skip; } break; case EOF: clearerr(stdin); ch = 0x1b; waiting = '['; break; default: ch = 0x1b; break; } break; default: goto skip; } } } #endif if (ch == '\n') { ch = '\r'; } return ch; } void TTSendMsg(unsigned int msg, int x, int y, unsigned int msgtype) { if (((ebufin + 1) % EBUFSZ) != ebufout) { EVent[ebufin].msg = msg; EVent[ebufin].x = x; EVent[ebufin].y = y; EVent[ebufin].msgtype = msgtype; ebufin = (ebufin + 1) % EBUFSZ; } } static volatile int jump_on_resize = 0; static jmp_buf jmpbuf; static void collect_events(int block) { int msg; #ifdef UNIX while (block) { if (setjmp(jmpbuf)) { block_console(0, 0); while (mykbhit()) waiting = -1; } if (waiting != -1) break; if (resize_pending != 0) break; block_console (1, 0); jump_on_resize = 1; waiting = getkey(); jump_on_resize = 0; if (waiting == EOF) { waiting = -1; clearerr(stdin); } } block_console (0, 0); if (resize_pending != 0) { TTSendMsg(resize_pending, 0, 0, WND_WM_RESIZE); resize_pending = 0; } #endif if (mykbhit() #ifndef UNIX || block #endif ) { msg = TTGetKey(); TTSendMsg(msg, 0, 0, WND_WM_CHAR); } } #ifdef UNIX void sigwinch_handler(int sig) { int newcol, newrow, i, x, y; struct winsize w; unsigned int *newbuf, *oldbuf; ioctl(fileno(stderr), TIOCGWINSZ, &w); newcol = w.ws_col; newrow = w.ws_row; if (newcol < MINTERMX) newcol = MINTERMX; if (newrow < MINTERMY) newrow = MINTERMY; for (i = 0; i <= 1; i++) { /* +3 to provide buffer for incorrect calls to the Win... routines if the window is very small */ newbuf = malloc((newcol + 3) * (newrow + 3) * sizeof(unsigned)); oldbuf = i ? scrnbuf : colbuf; if (newbuf == NULL) { TTkclose(); abort(); } for (y = 0; y < newrow; y++) { for (x = 0; x < newcol; x++) { if (x >= term.NCol || y >= term.NRow) { newbuf[y * newcol + x] = i ? ' ' : 0; } else { newbuf[y * newcol + x] = oldbuf[y * term.NCol + x]; } } } if (i) { free(scrnbuf); scrnbuf = newbuf; } else { free(colbuf); colbuf = newbuf; } } term.NCol = newcol; term.NRow = newrow; TTRepaint(); resize_pending = 1; #ifndef BSD /* need to reinstall the handler */ signal (sig, sigwinch_handler); #endif if (jump_on_resize) { jump_on_resize = 0; longjmp(jmpbuf, 1); } } #endif int TTkopen(void) { int x; #ifdef UNIX struct termios tios; struct winsize w; #if 1 ioctl(fileno(stderr), TIOCGWINSZ, &w); if (w.ws_row > MINTERMY) term.NRow = w.ws_row; if (w.ws_col > MINTERMY) term.NCol = w.ws_col; #endif #endif if (term.NRow < MINTERMY) term.NRow = MINTERMY; if (term.NCol < MINTERMX) term.NCol = MINTERMX; #ifdef SASC coninit(); #endif #ifdef UNIX tcgetattr(0, &tios); oldtios = tios; tios.c_lflag &= ~(ICANON | ISIG); tios.c_lflag &= ~ECHO; tcsetattr(0, TCSANOW, &tios); block_console(0,0); setbuf(stdin, NULL); #ifdef sun initscr(); /* curses initialization */ cbreak(); noecho(); #endif #endif /* +3 to provide buffer for incorrect calls to the Win... routines if the window is very small */ scrnbuf = malloc((term.NRow + 3) * (term.NCol + 3) * sizeof(unsigned)); colbuf = malloc((term.NRow + 3) * (term.NCol + 3) * sizeof(unsigned)); if (scrnbuf == NULL || colbuf == NULL) { TTkclose(); fprintf (stderr, "Out of memory!\n"); abort(); } for (x = 0; x < term.NRow * term.NCol; x++) { scrnbuf[x] = ' '; colbuf[x] = 11; } #if 1 #ifdef UNIX signal (SIGWINCH, sigwinch_handler); #endif #endif #ifdef UNIX query_termcap(tcflags); #endif return 0; } static void TTRepaint(void) { int x,y, xp, yp, oldcol, col, c; xp = vcol; yp = vrow; oldcol = col = color; TTgotoxy_noflush(0,0); fputs("\033[2J", stdout); for (y = 0; y < term.NRow; y++) { for (x = 0; x < term.NCol; x++) { if (colbuf[y * term.NCol + x] != col) { TTScolor(col = colbuf[y * term.NCol + x]); } if (x != term.NCol -1 || y != term.NRow -1) { c = scrnbuf[y * term.NCol + x]; putchar(c); } else { fputs("\033[K", stdout); } } } TTgotoxy(yp, xp); TTScolor(oldcol); fflush(stdout); } int TTkclose(void) { TTScolor(0x07); #ifdef SASC confin(); fputs("\033[31m", stdout); #else fputs("\033[0m\033[1;1H\033[J", stdout); #endif #ifdef UNIX signal (SIGWINCH, SIG_DFL); tcsetattr(0, TCSANOW, &oldtios); #endif fflush(stdout); if (scrnbuf != NULL) { free(scrnbuf); scrnbuf = NULL; } if (colbuf != NULL) { free(colbuf); colbuf = NULL; } /* if (allowed_special_characters != NULL) { free(allowed_special_characters); allowed_special_characters = NULL; } we don't free this list, so that it is available in case the calling program should call TTclose and then TTopen in sequence (e.g. when it does a DOS shell) */ return 0; } void MouseOFF(void) { } void MouseON(void) { } void MouseInit(void) { } int GetMouInfo(int *x, int *y) { unused(x); unused(y); return 0; } int TTGetMsg(EVT * e) { while (ebufin == ebufout) { collect_events(1); } e->msg = EVent[ebufout].msg; e->x = EVent[ebufout].x; e->y = EVent[ebufout].y; e->msgtype = EVent[ebufout].msgtype; e->id = 0; ebufout = (ebufout + 1) % EBUFSZ; return e->msg; } int TTPeekQue(void) { collect_events(0); return ebufin != ebufout; } void TTClearQue(void) { ebufin = ebufout; } int TTGetChr(void) { EVT e; TTGetMsg(&e); return e.msg; } int TTopen(void) { vcol = vrow = 0; color = 0x07; TTkopen(); return 1; } int TTclose(void) { TTkclose(); return 1; } /* * Configure the terminal. Configuration is retained even after TTclose. * * The ANSI/VT100 terminal accepts the following configuration keywords: * * keyword possible values * * highascii A string of high ascii bytes that, if read from the key- * board shall be reported verbatim to the calling application, * instead of being interpreted as combination of the Meta key * with a low ASCII key. You will need to enable high ascii * alphabet characters (like umlauts or cyrillics) with this. * An empty string is the deafault. * * highascii Either "1" or "0". If 1, the termcap database is queried * to see if there is pseudographics support (as, ac and ae * entires), and if so , it is enabled. If 0, pseudographics * is always disabled. "0" is the default. */ int TTconfigure(const char *keyword, const char *value) { size_t l; if (!strcmp(keyword,"highascii")) { if (allowed_special_characters != NULL) { free(allowed_special_characters); } allowed_special_characters = (unsigned char *) malloc(l = (strlen(value) + 1)); memcpy(allowed_special_characters, value, l); } else if (!strcmp(keyword,"pseudographics")) { if (atoi(value)) { tcflags |= QUERY_ALTCHARSET; } else { tcflags &= ~QUERY_ALTCHARSET; } query_termcap(tcflags); } else { return 0; } return 1; } static int mykbhit(void) { int ret; if (FullBuffer()) { return 0; } #ifdef SASC ret = akbhit(); #elif defined UNIX if (waiting == -1) { waiting = getkey(); if (waiting == EOF) { waiting = -1; clearerr(stdin); } } ret = (waiting != -1); #else ret = kbhit(); #endif return ret; } int dv_running(void) { return 0; } static int FullBuffer(void) { if (((ebufin + 1) % EBUFSZ) != ebufout) { return 0; } else { return 1; } } #endif