#include "config.h" #include #ifndef VMS #include #endif #ifndef sequent # ifndef NO_STDLIB_H # include # endif #endif #ifndef NO_UNISTD_H #include #endif #include #include "most.h" #include "buffer.h" #include "display.h" #include "sysdep.h" #include "window.h" int Most_Screen_Width = 80; int Most_Screen_Height = 24; int Most_Term_Cannot_Insert = 0; /* 1 if terminal lacks the ability to do into insert mode or into delete mode. Currently controlled by S-Lang but later perhaps termcap. */ int Most_Term_Cannot_Scroll = 0; char *Most_TT_Bold_Str; /* = "\033[1m"; */ /* md */ char *Most_TT_Norm_Str; /* = "\033[0m"; */ /* me */ char *Most_TT_Ulin_Str; /* = "\033[4m"; */ /* us */ char *Most_Curs_F_Str; /* = "\033[%dC"; */ /* RI termcap string */ static char *Ins_Mode_Str; /* = "\033[4h"; */ /* ins mode (im) */ static char *Eins_Mode_Str; /* = "\033[4l"; */ /* end ins mode (ei) */ static char *Scroll_R_Str; /* = "\033[%d;%dr"; */ /* scroll region */ static char *Cls_Str; /* = "\033[2J\033[H"; */ /* cl termcap STR for ansi terminals */ static char *Del_Eol_Str; /* = "\033[K"; */ /* ce */ static char *Del_Char_Str; /* = "\033[P"; */ /* dc */ static char *Del_N_Lines_Str; /* = "\033[%dM"; */ /* DL */ static char *Add_N_Lines_Str; /* = "\033[%dL"; */ /* AL */ static char *Rev_Scroll_Str; static char *TT_Rev_Vid_Str; /* = "\033[7m"; */ /* mr */ static int Len_Curs_F_Str = 5; /* cm string has %i%d since termcap numbers columns from 0 */ /* char *CURS_POS_STR = "\033[%d;%df"; ansi-- hor and vert pos */ static char *Curs_Pos_Str; /* = "\033[%i%d;%dH";*/ /* cm termcap string */ /* scrolling region */ static int Scroll_r1 = 0, Scroll_r2 = 23; static int Cursor_r; void most_tt_write(char *str, int n) { /* static unsigned long last_time; static int total; unsigned long now; */ if (str == NULL) return; /* total += n; */ write(fileno(stdout), str, n); /* if ((Output_Rate > 20) && (total > Output_Rate)) { total = 0; if ((now = sys_time()) - last_time <= 1) { sleep((unsigned) 1); } last_time = now; } */ } void most_send_string_to_term(char *str) { if (str == NULL) return; most_tt_write(str, strlen(str)); } void most_tt_putchar(char ch) { #if !defined(VMS) && !HAS_TERMIOS write(fileno(stdout), &ch, 1); if (ch == '\n') ch = '\r'; else return; #endif write(fileno(stdout), &ch, 1); } /* this is supposed to be fast--- also handles termcap: %d, &i, %., %+, %r strings as well as terminfo stuff */ int most_tt_sprintf(char *buf, char *fmt, int x, int y) { register unsigned char *f = (unsigned char *) fmt, *b, ch; int offset = 0, tinfo = 0; int stack[10]; int i = 0, z; stack[0] = y; stack[1] = x; i = 2; b = (unsigned char *) buf; if (fmt != NULL) while ((ch = *f++) != 0) { if (ch != '%') *b++ = ch; else { ch = *f++; if (tinfo) { if ((ch <= '3') && (ch >= '0')) { /* map it to termcap. SInce this is terminfo, * it must be one of: * %2d, %3d, %02d, %03d * */ /* skip the 'd'-- hope it is there */ if (ch == '0') { ch = *f; f += 2; } else f++; } } if (ch == 'p') { tinfo = 1; ch = *f++; if (ch == '1') stack[i++] = x; else stack[i++] = y; } else if (ch == '\'') /* 'x' */ { stack[i++] = *f++; f++; } else if ((ch == 'd') || (ch == '2') || (ch == '3')) { z = stack[--i]; z += offset; if (z >= 100) { *b++ = z / 100 + '0'; z = z % 100; goto ten; } else if (ch == '3') { *b++ = '0'; ch = '2'; } if (z >= 10) { ten: *b++ = z / 10 + '0'; z = z % 10; } else if (ch == '2') *b++ = '0'; *b++ = z + '0'; } else if (ch == 'i') { offset = 1; } else if (ch == '+') { if (tinfo) { z = stack[--i]; stack[i-1] += z; } else { ch = *f++; if ((unsigned char) ch == 128) ch = 0; ch = ch + (unsigned char) stack[--i]; if (ch == '\n') ch++; *b++ = ch; } } else if (ch == 'r') { stack[0] = x; stack[1] = y; } else if ((ch == '.') || (ch == 'c')) { ch = (unsigned char) stack[--i]; if (ch == '\n') ch++; *b++ = ch; } else *b++ = ch; } } *b = 0; return((int) (b - (unsigned char *) buf)); } static void tt_printf(char *fmt, int x, int y) { char buf[256]; int n; n = most_tt_sprintf(buf, fmt, x, y); most_tt_write(buf, n); } void most_curs_bol (void) { most_tt_putchar('\r'); } void most_set_scroll_region(int r1, int r2) { Scroll_r1 = r1 - 1; Scroll_r2 = r2 - 1; tt_printf(Scroll_R_Str,Scroll_r1, Scroll_r2); } /* the goto_rc function moves to row relative to scrolling region */ void most_goto_rc(int r, int c) { Cursor_r = r - 1 + Scroll_r1; tt_printf(Curs_Pos_Str, Cursor_r,c - 1); } #if 0 static void begin_insert(void) { most_send_string_to_term(Ins_Mode_Str); } static void end_insert(void) { most_send_string_to_term(Eins_Mode_Str); } static void tt_delete_char(void) { most_send_string_to_term(Del_Char_Str); } #endif void most_tt_erase_line(void) { most_curs_bol(); most_send_string_to_term(Del_Eol_Str); } void most_tt_delete_nlines(int n) { int r1, curs; if (!n) return; if (Del_N_Lines_Str != NULL) tt_printf(Del_N_Lines_Str,n, 0); else /* get a new terminal */ { r1 = Scroll_r1 + 1; curs = Cursor_r + 1; most_set_scroll_region(curs, Scroll_r2 + 1); most_goto_rc(Scroll_r2 - Scroll_r1 + 1, 1); while (n--) most_tt_putchar('\n'); most_set_scroll_region(r1, Scroll_r2 + 1); most_goto_rc(curs, 1); } } void most_cls(void) { most_send_string_to_term(Cls_Str); } void most_reverse_index(int n) { if (!n) return; if (Add_N_Lines_Str != NULL) tt_printf(Add_N_Lines_Str,n, 0); else { while(n--) most_send_string_to_term(Rev_Scroll_Str); } } void most_beep(void) { most_tt_putchar('\007'); } static void tt_del_eol(void) { most_send_string_to_term(Del_Eol_Str); } void most_tt_reverse_video(void) { most_send_string_to_term(TT_Rev_Vid_Str); } void most_tt_bold_video (void) { most_send_string_to_term(Most_TT_Bold_Str); } void most_tt_normal_video(void) { most_send_string_to_term(Most_TT_Norm_Str); } void most_narrow_width(void) { most_send_string_to_term("\033[?3l"); } void most_wide_width(void) { most_send_string_to_term("\033[?3h"); } void most_smart_puts(char *neww,char *oldd, int row, int spc) { char out[250], curs[20], *mark; register char *p, ch, ch1; register char *neew = neww, *old = oldd; int ii,max_len,i, curs_set = 0, curs_len = 0; char *new_save; i = 0; ii = 0; *curs = 0; max_len = Len_Curs_F_Str; /* many times we are scrolling and line to compare is blank. Treat this case special */ if (spc == 0) { p = neew; while(*p == ' ') p++; if (*p == 0) return; most_goto_rc(row, p - neew + 1); old = out; ch1 = ' '; while (1) { while (ch = *p++, (ch1 != ch) && ch) *old++ = ch; mark = old; if (!ch) break; *old++ = ch1; while(ch = *p++, (ch == ch1) && ch) *old++ = ch; if (old - mark > max_len) { *mark = 0; most_send_string_to_term(out); if (ch == 0) return; if (mark != out) most_goto_rc(row, p - neew); old = out; } if (!ch) break; p--; } *old = 0; most_send_string_to_term(out); return; } /* while they match, go on */ /* Note that neew - new_save is then column of character */ new_save = neew + 1; while (((ch = *neew++) == *old++) && ch); i += neew - new_save; if (!ch) /* we are at the end of the new, so delete eond of old line */ { if ((ch1 = *(old - 1)) == ' ') { while (*old++ == ch1); ch1 = *(old - 1); } if (ch1 == 0) return; most_goto_rc(row, i + 1); tt_del_eol(); return; } if (i) { curs_len = most_tt_sprintf(curs, Curs_Pos_Str, row - 1, i); curs_set = 1; } while(1) { ch1 = 0; p = out; *p++ = ch; while (ch1 = *old++, ch = *neew++, (ch != ch1) && ch) *p++ = ch; mark = p; *p++ = ch; if (ch) while (ch = *neew++, ch1 = *old++, (ch == ch1) && ch) { *p++ = ch; } *p = 0; i = p - mark; if (i > max_len) { *mark = 0; if (*curs) { most_tt_write(curs, curs_len); *curs = 0; } if (!curs_set) { most_goto_rc(row, 1); curs_set = 1; } most_send_string_to_term(out); if (!ch) { if (ch1) { old--; ch = ' '; while (ch1 = *old++, (ch1 == ch)); } if (ch1 == 0) return; if (curs_set && (Most_Curs_F_Str != NULL)) tt_printf(Most_Curs_F_Str, i, 0); else { tt_printf(Curs_Pos_Str, row - 1, neew - new_save); curs_set = 1; } tt_del_eol(); return; } if (i) { if (curs_set && (Most_Curs_F_Str != NULL)) curs_len = most_tt_sprintf(curs, Most_Curs_F_Str, i, 0); else { curs_len = most_tt_sprintf(curs, Curs_Pos_Str, row - 1, neew - new_save); curs_set = 1; } } } else { if (*curs) { most_tt_write(curs, curs_len); *curs = 0; } if (!curs_set) { most_goto_rc(row, 1); curs_set = 1; } most_send_string_to_term(out); if (!ch) { if (ch1 == ' ') { while (*old++ == ch1); ch1 = *(old - 1); } if (ch1) tt_del_eol(); return; } } } } static int vt100_like = 0; void most_set_term_vtxxx (int); /* termcap stuff */ #ifdef unix extern char *tgetstr(char *, char **); extern int tgetent(char *, char *); extern int tgetnum(char *); static char tbuf[1024]; static char *Null_String = ""; static char *my_tgetstr(char *what, char **p) { register char *w, *w1; char *wsave; what = tgetstr(what, p); if (what != NULL) { /* lose pad info --- with today's technology, term is a loser if it is really needed */ while ((*what == '.') || ((*what >= '0') && (*what <= '9'))) what++; if (*what == '*') what++; /* lose terminfo padding--- looks like $<...> */ w = what; while (*w) if ((*w++ == '$') && (*w == '<')) { w1 = w - 1; while (*w && (*w != '>')) w++; if (*w == 0) break; w++; wsave = w1; while ((*w1++ = *w++) != 0); w = wsave; } if (*what == 0) what = NULL; } return(what); } static char tstr_buf[512]; void most_get_terminfo(void) { char *t, *term, ch; char *p = tstr_buf; if (NULL == (term = getenv("TERM"))) { most_exit_error("TERM environment variable needs set."); } if (1 != tgetent(tbuf, term)) most_exit_error("Unknown terminal."); if ((Most_Screen_Width = tgetnum("co")) <= 0) Most_Screen_Width = 80; if ((Most_Screen_Height = tgetnum("li")) <= 0) Most_Screen_Height = 24; t = term; if (strcmp(t, "vt52") && (*t++ == 'v') && (*t++ == 't') && (ch = *t, (ch >= '1') && (ch <= '9'))) { vt100_like = 1; /* make up for DEC'S braindead termcaps (probably most other unix too) */ if ((ch >= 2) || !strcmp(t, "102")) { most_set_term_vtxxx(0); return; } } if ((NULL == (Cls_Str = my_tgetstr("cl", &p))) || (NULL == (Curs_Pos_Str = my_tgetstr("cm", &p)))) { most_exit_error("Terminal not powerful enough for MOST."); } if ((NULL == (Ins_Mode_Str = my_tgetstr("im", &p))) || ( NULL == (Eins_Mode_Str = my_tgetstr("ei", &p))) || ( NULL == (Del_Char_Str = my_tgetstr("dc", &p)))) Most_Term_Cannot_Insert = 1; Rev_Scroll_Str = my_tgetstr("sr", &p); Del_N_Lines_Str = my_tgetstr("DL", &p); Add_N_Lines_Str = my_tgetstr("AL", &p); Scroll_R_Str = my_tgetstr("cs", &p); if ((Scroll_R_Str == NULL) || (((NULL == Del_N_Lines_Str) || (NULL == Add_N_Lines_Str)) && (NULL == Rev_Scroll_Str))) Most_Term_Cannot_Scroll = 1; #ifdef __linux__ if (!strcmp(term, "console")) Most_Term_Cannot_Scroll = 1; #endif Del_Eol_Str = my_tgetstr("ce", &p); /* so, se */ if (NULL == (TT_Rev_Vid_Str = my_tgetstr("mr", &p))) TT_Rev_Vid_Str = Null_String; if (NULL == (Most_TT_Bold_Str = my_tgetstr("md", &p))) Most_TT_Bold_Str = Null_String; if (NULL == (Most_TT_Norm_Str = my_tgetstr("me", &p))) Most_TT_Norm_Str = Null_String; if (NULL == (Most_TT_Ulin_Str = my_tgetstr("us", &p))) Most_TT_Ulin_Str = Null_String; if (NULL != (Most_Curs_F_Str = my_tgetstr("RI", &p))) { Len_Curs_F_Str = strlen(Most_Curs_F_Str); } else Len_Curs_F_Str = strlen(Curs_Pos_Str); } #endif /* specific to vtxxx only */ void most_enable_cursor_keys(void) { if (vt100_like) most_send_string_to_term("\033=\033[?1l"); } /* This sets term for vt102 terminals it parameter vt100 is 0. If vt100 is non-zero, set terminal appropriate for a only vt100 (no add line capability). */ void most_set_term_vtxxx(int is_vt100) { vt100_like = 1; Scroll_R_Str = "\033[%i%d;%dr"; Cls_Str = "\033[2J\033[H"; TT_Rev_Vid_Str = "\033[7m"; Most_TT_Norm_Str = "\033[m"; Most_TT_Bold_Str = "\033[1m"; Most_TT_Ulin_Str = "\033[4m"; Del_Eol_Str = "\033[K"; Rev_Scroll_Str = "\033M"; Most_Curs_F_Str = "\033[%dC"; Curs_Pos_Str = "\033[%i%d;%dH"; if (!is_vt100) { Del_N_Lines_Str = "\033[%dM"; Ins_Mode_Str = "\033[4h"; Eins_Mode_Str = "\033[4l"; Del_Char_Str = "\033[P"; Add_N_Lines_Str = "\033[%dL"; } else { Del_N_Lines_Str = NULL; Ins_Mode_Str = NULL; Eins_Mode_Str = NULL; Del_Char_Str = NULL; Add_N_Lines_Str = NULL; } most_get_term_dimensions(&Most_Screen_Width, &Most_Screen_Height); Most_Term_Cannot_Insert = 0; most_enable_cursor_keys(); }