/****************************************************************************** * TinTin++ * * Copyright (C) 2004 (See CREDITS file) * * * * This program is protected under the GNU GPL (See COPYING) * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the Free Software * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * *******************************************************************************/ /****************************************************************************** * (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t * * * * coded by Igor van den Hoven 2004 * ******************************************************************************/ #include "tintin.h" void save_pos(struct session *ses) { printf("\0337"); ses->sav_row = ses->cur_row; ses->sav_col = ses->cur_col; } void restore_pos(struct session *ses) { printf("\0338\0338"); ses->cur_row = ses->sav_row; ses->cur_col = ses->sav_col; } void restore_cursor(struct session *ses) { printf("\033[%d;%dH", ses->rows, gtd->input_pos+1); } void goto_rowcol(struct session *ses, int row, int col) { printf("\033[%d;%dH", row, col); ses->cur_row = row; } void erase_toeol(void) { printf("\033[K"); } /* save cursor, goto top row, delete (bot - top) rows, restore cursor */ void erase_screen(struct session *ses) { printf("\0337\033[%d;1H\033[%dM\0338", ses->top_row, ses->bot_row - ses->top_row); ses->sav_row = ses->cur_row; ses->sav_col = ses->cur_col; } /* doesn't do much */ void reset(void) { printf("%cc", ESCAPE); } void scroll_region(struct session *ses, int top, int bot) { printf("%c[%d;%dr", ESCAPE, top, bot); ses->top_row = top; ses->bot_row = bot; } void reset_scroll_region(struct session *ses) { if (ses == gtd->ses) { printf("%c[r", ESCAPE); } ses->top_row = 1; ses->bot_row = ses->rows; } int skip_vt102_codes(char *str) { int skip; push_call("skip_vt102_codes(%p)",str); switch (str[0]) { case 5: /* ENQ */ case 7: /* BEL */ case 8: /* BS */ /* case 9: *//* HT */ /* case 10: *//* LF */ case 11: /* VT */ case 12: /* FF */ case 13: /* CR */ case 14: /* SO */ case 15: /* SI */ case 17: /* DC1 */ case 19: /* DC3 */ case 24: /* CAN */ case 26: /* SUB */ case 127: /* DEL */ pop_call(); return 1; case 27: /* ESC */ break; default: pop_call(); return 0; } switch (str[1]) { case '\0': pop_call(); return 1; case '%': case '#': case '(': case ')': pop_call(); return str[2] ? 3 : 2; case ']': switch (str[2]) { case 'P': for (skip = 3 ; skip < 10 ; skip++) { if (str[skip] == 0) { break; } } pop_call(); return skip; case 'R': pop_call(); return 3; } pop_call(); return 2; case '[': break; default: pop_call(); return 2; } for (skip = 2 ; str[skip] != 0 ; skip++) { if (isalpha((int) str[skip])) { pop_call(); return skip + 1; } switch (str[skip]) { case '@': case '`': case ']': pop_call(); return skip + 1; } } pop_call(); return skip; } int find_non_color_codes(char *str) { int skip; switch (str[0]) { case 27: /* ESC */ break; default: return 0; } switch (str[1]) { case '[': break; default: return 0; } for (skip = 2 ; str[skip] != 0 ; skip++) { switch (str[skip]) { case 'm': return skip + 1; case '@': case '`': case ']': return 0; } if (isalpha((int) str[skip])) { return 0; } } return 0; } int skip_vt102_codes_non_graph(char *str) { int skip = 0; switch (str[skip]) { case 5: /* ENQ */ case 7: /* BEL */ /* case 8: *//* BS */ /* case 9: *//* HT */ /* case 10: *//* LF */ case 11: /* VT */ case 12: /* FF */ case 13: /* CR */ case 14: /* SO */ case 15: /* SI */ case 17: /* DC1 */ case 19: /* DC3 */ case 24: /* CAN */ case 26: /* SUB */ case 127: /* DEL */ return 1; case 27: /* ESC */ break; default: return 0; } switch (str[1]) { case '\0': return 0; case 'c': case 'D': case 'E': case 'H': case 'M': case 'Z': case '7': case '8': case '>': case '=': return 2; case '%': case '#': case '(': case ')': return 3; case ']': switch (str[2]) { case 'P': return 10; case 'R': return 3; } return 2; case '[': break; default: return 2; } for (skip = 2 ; str[skip] != 0 ; skip++) { switch (str[skip]) { case 'm': return 0; case '@': case '`': case ']': return skip + 1; } if (isalpha((int) str[skip])) { return skip + 1; } } return 0; } void strip_vt102_codes(char *str, char *buf) { char *pti, *pto; pti = (char *) str; pto = (char *) buf; while (*pti) { while (skip_vt102_codes(pti)) { pti += skip_vt102_codes(pti); } if (*pti) { *pto++ = *pti++; } } *pto = 0; } void strip_vt102_codes_non_graph(char *str, char *buf) { char *pti, *pto; pti = str; pto = buf; while (*pti) { while (skip_vt102_codes_non_graph(pti)) { pti += skip_vt102_codes_non_graph(pti); } if (*pti) { *pto++ = *pti++; } } *pto = 0; } void strip_non_vt102_codes(char *str, char *buf) { char *pti, *pto; int len; pti = str; pto = buf; while (*pti) { while ((len = skip_vt102_codes(pti)) != 0) { memcpy(pto, pti, len); pti += len; pto += len; } if (*pti) { pti++; } } *pto = 0; } // mix old and str, then copy compressed color string to buf which can point to old. void get_color_codes(char *old, char *str, char *buf) { char *pti, *pto, col[100], tmp[BUFFER_SIZE]; int len, vtc, fgc, bgc, cnt; pto = tmp; pti = old; while (*pti) { while ((len = find_non_color_codes(pti)) != 0) { memcpy(pto, pti, len); pti += len; pto += len; } if (*pti) { pti++; } } pti = str; while (*pti) { while ((len = find_non_color_codes(pti)) != 0) { memcpy(pto, pti, len); pti += len; pto += len; } if (*pti) { pti++; } } *pto = 0; if (strlen(tmp) == 0) { buf[0] = 0; return; } vtc = 0; fgc = -1; bgc = -1; pti = tmp; while (*pti) { switch (*pti) { case 27: pti += 2; if (pti[-1] == 'm') { vtc = 0; fgc = -1; bgc = -1; break; } for (cnt = 0 ; pti[cnt] ; cnt++) { col[cnt] = pti[cnt]; if (pti[cnt] == ';' || pti[cnt] == 'm') { col[cnt] = 0; cnt = -1; pti += 1 + strlen(col); if (HAS_BIT(vtc, COL_256) && (HAS_BIT(vtc, COL_XTF) || HAS_BIT(vtc, COL_XTB))) { if (HAS_BIT(vtc, COL_XTF)) { fgc = URANGE(0, atoi(col), 255); } if (HAS_BIT(vtc, COL_XTB)) { bgc = URANGE(0, atoi(col), 255); } DEL_BIT(vtc, COL_XTF|COL_XTB); } else { switch (atoi(col)) { case 0: vtc = 0; fgc = -1; bgc = -1; break; case 1: SET_BIT(vtc, COL_BLD); break; case 4: SET_BIT(vtc, COL_UND); break; case 5: if (HAS_BIT(vtc, COL_XTF) || HAS_BIT(vtc, COL_XTB)) { SET_BIT(vtc, COL_256); } else { SET_BIT(vtc, COL_BLK); } break; case 7: SET_BIT(vtc, COL_REV); break; case 2: case 21: case 22: DEL_BIT(vtc, COL_BLD); break; case 24: DEL_BIT(vtc, COL_UND); break; case 25: DEL_BIT(vtc, COL_UND); break; case 27: DEL_BIT(vtc, COL_BLK); break; case 38: DEL_BIT(vtc, COL_XTB); DEL_BIT(vtc, COL_256); SET_BIT(vtc, COL_XTF); fgc = -1; break; case 39: DEL_BIT(vtc, COL_UND); fgc = -1; break; case 48: DEL_BIT(vtc, COL_XTF); DEL_BIT(vtc, COL_256); SET_BIT(vtc, COL_XTB); bgc = -1; break; default: DEL_BIT(vtc, COL_256); /* Use 256 color's 16 color notation */ if (atoi(col) / 10 == 4) { bgc = atoi(col) % 10; } if (atoi(col) / 10 == 9) { bgc = atoi(col) % 10 + 8; } if (atoi(col) / 10 == 3) { fgc = atoi(col) % 10; } if (atoi(col) / 10 == 10) { fgc = atoi(col) % 10 + 8; } break; } } } if (pti[-1] == 'm') { break; } } break; default: pti++; break; } } strcpy(buf, "\033[0"); if (HAS_BIT(vtc, COL_BLD)) { strcat(buf, ";1"); } if (HAS_BIT(vtc, COL_UND)) { strcat(buf, ";4"); } if (HAS_BIT(vtc, COL_BLK)) { strcat(buf, ";5"); } if (HAS_BIT(vtc, COL_REV)) { strcat(buf, ";7"); } if (fgc >= 16) { cat_sprintf(buf, ";38;5;%d", fgc); } else if (fgc >= 8) { cat_sprintf(buf, ";%d", fgc + 100); } else if (fgc >= 0) { cat_sprintf(buf, ";%d", fgc + 30); } if (bgc >= 16) { cat_sprintf(buf, ";48;5;%d", bgc); } else if (bgc >= 8) { cat_sprintf(buf, ";%d", fgc + 90); } else if (bgc >= 0) { cat_sprintf(buf, ";%d", bgc + 40); } strcat(buf, "m"); } int strip_vt102_strlen(char *str) { char *pti; int i = 0; pti = str; while (*pti) { while (skip_vt102_codes(pti)) { pti += skip_vt102_codes(pti); } if (*pti) { pti++; i++; } } return i; } int strip_color_strlen(char *str) { char *pti; int i = 0; pti = str; while (*pti) { if (pti[0] == '<' && isalnum((int) pti[1]) && isalnum((int) pti[2]) && isalnum((int) pti[3]) && pti[4] == '>') { pti += 5; } else { pti++; i++; } } return i; } int interpret_vt102_codes(struct session *ses, char *str, int real) { char data[BUFFER_SIZE] = { 0 }; int skip = 0; switch (str[skip]) { case 5: return FALSE; /* ^E fucks with the terminal */ case 8: ses->cur_col = UMAX(1, ses->cur_col - 1); return TRUE; case 27: /* ESC */ break; case 13: /* CR */ ses->cur_col = 1; default: return TRUE; } switch (str[1]) { case '7': ses->sav_row = ses->cur_row; ses->sav_col = ses->cur_col; return TRUE; case '8': ses->cur_row = ses->sav_row; ses->cur_col = ses->sav_col; return TRUE; case 'D': ses->cur_row = URANGE(1, ses->cur_row + 1, ses->rows); return TRUE; case 'E': ses->cur_row = URANGE(1, ses->cur_row + 1, ses->rows); ses->cur_col = 1; return TRUE; case 'M': ses->cur_row = URANGE(1, ses->cur_row - 1, ses->rows); return TRUE; case 'Z': if (real) { socket_printf(ses, 5, "%c%c%c%c%c", ESCAPE, '[', '?', '6', 'c'); } return FALSE; case '[': break; default: return TRUE; } for (skip = 2 ; str[skip] != 0 ; skip++) { switch (str[skip]) { case '@': case '`': case ']': return TRUE; case 'c': if (real) { socket_printf(ses, 5, "%c%c%c%c%c", ESCAPE, '[', '?', '6', 'c'); } ses->cur_row = 1; ses->cur_col = 1; ses->sav_row = ses->cur_row; ses->sav_col = ses->cur_col; return FALSE; case 'A': ses->cur_row -= UMAX(1, atoi(data)); break; case 'B': case 'e': ses->cur_row += UMAX(1, atoi(data)); break; case 'C': case 'a': ses->cur_col += UMAX(1, atoi(data)); break; case 'D': ses->cur_col -= UMAX(1, atoi(data)); break; case 'E': ses->cur_row -= UMAX(1, atoi(data)); ses->cur_col = 1; break; case 'F': ses->cur_row -= UMAX(1, atoi(data)); ses->cur_col = 1; break; case 'G': ses->cur_col = UMAX(1, atoi(data)); break; case 'H': case 'f': if (sscanf(data, "%d;%d", &ses->cur_row, &ses->cur_col) != 2) { if (sscanf(data, "%d", &ses->cur_row) == 1) { ses->cur_col = 1; } else { ses->cur_row = 1; ses->cur_col = 1; } } break; case 'd': ses->cur_row = atoi(data); break; case 'r': if (sscanf(data, "%d;%d", &ses->top_row, &ses->bot_row) != 2) { if (sscanf(data, "%d", &ses->top_row) != 1) { ses->top_row = 1; ses->bot_row = ses->rows; } else { ses->bot_row = ses->rows; } } ses->cur_row = 1; ses->cur_col = 1; break; case 's': ses->sav_row = ses->cur_row; ses->sav_col = ses->cur_col; break; case 'u': ses->cur_row = ses->sav_row; ses->cur_col = ses->sav_col; break; default: data[skip - 2] = str[skip]; data[skip - 1] = 0; break; } if (isalpha((int) str[skip])) { ses->cur_row = URANGE(1, ses->cur_row, ses->rows); ses->cur_col = URANGE(1, ses->cur_col, ses->cols + 1); ses->top_row = URANGE(1, ses->top_row, ses->rows); ses->bot_row = ses->bot_row ? URANGE(1, ses->bot_row, ses->rows) : ses->rows; return TRUE; } } return TRUE; }