done till colors ...
[midnight-commander.git] / slang / sldisply.c
blob4ad93c437068dcb58bba0ed9f37784e50c5cdf71
1 /* Copyright (c) 1992, 1995 John E. Davis
2 * All rights reserved.
3 *
4 * You may distribute under the terms of either the GNU General Public
5 * License or the Perl Artistic License.
6 */
8 /*
9 * SLTT_TRANSP_ACS_PATCH (#define/#undef):
11 * The problem: some terminals (e.g. QNX/qansi*) map the whole upper half of
12 * the ASCII table to the lower half, when alt-char-set is activated with
13 * the smacs/as string-sequence. This means, that if 0 <= ch < 128 written
14 * to the terminal, it will be translated to (ch+128) automatically by the
15 * terminal: so not only the line-drawing characters can be written, when
16 * the alt-char-set is activated. It implicitly means, that space, NL, CR,
17 * etc. characters (exactly: anything besides the "standard" line drawing
18 * characters) can not be written directly to the terminal, when the
19 * alt-char-set is activated, because writing these characters doesn't cause
20 * an implicit/temporary switching-back to the standard char-set!
22 * The original code in SLang assumes that space, NL, CR, etc. can be
23 * printed when alt-char-set is activated. If SLTT_TRANSP_ACS_PATCH is
24 * defined, the modified code will not use this assumption.
25 * [Remark: the patch-code is not the most exact solution, but works...]
27 /*#define SLTT_TRANSP_ACS_PATCH 1*/
30 * QNX_QANSI_SLANG_COMPAT_ACS (#define/#undef):
32 * A more OS/terminal-specific solution for the problem mentioned above
33 * (->SLTT_TRANSP_ACS_PATCH).
35 * If QNX_QANSI_SLANG_COMPAT_ACS is defined, the default smacs/sa, rmacs/ae,
36 * acsc/ac [and sgr/sa, if it would be used!] command sequences will be
37 * replaced internally with the "old style" (pre-QNX 4.23) sequences in case
38 * of QNX/qansi terminals. Using these optional command sequences the terminal
39 * remains compatible with the original SLang code (without using the
40 * workaround-code enabled by defining SLTT_TRANSP_ACS_PATCH).
42 /*#define QNX_QANSI_SLANG_COMPAT_ACS 1*/
44 /* auto-configuration */
45 #ifdef SLTT_TRANSP_ACS_PATCH
46 # if defined(__QNX__) && defined(QNX_QANSI_SLANG_COMPAT_ACS)
47 # undef SLTT_TRANSP_ACS_PATCH
48 # endif
49 #else
50 # if defined(__QNX__) && !defined(QNX_QANSI_SLANG_COMPAT_ACS)
51 # define QNX_QANSI_SLANG_COMPAT_ACS 1
52 # endif
53 #endif
55 #include "sl-feat.h"
56 #include "config.h"
58 #include <stdio.h>
59 #include <string.h>
60 #ifdef SCO_FLAVOR
61 # include <sys/types.h>
62 # include <sys/timeb.h> /* for struct timeb, used in time.h */
63 #endif
64 #include <time.h>
65 #include <ctype.h>
67 #ifndef VMS
68 # include <sys/time.h>
69 # ifdef __QNX__
70 # include <sys/select.h>
71 # endif
72 # include <sys/types.h>
73 #endif
75 #ifdef __BEOS__
76 /* Prototype for select */
77 # include <net/socket.h>
78 #endif
80 #ifdef HAVE_TERMIOS_H
81 # include <termios.h>
82 #endif
84 #ifdef VMS
85 # include <unixlib.h>
86 # include <unixio.h>
87 # include <dvidef.h>
88 # include <descrip.h>
89 # include <lib$routines.h>
90 # include <starlet.h>
91 #else
92 # if !defined(sun)
93 # include <sys/ioctl.h>
94 # endif
95 #endif
98 #ifdef SYSV
99 # include <sys/termio.h>
100 # include <sys/stream.h>
101 # include <sys/ptem.h>
102 # include <sys/tty.h>
103 #endif
105 #if defined (_AIX) && !defined (FD_SET)
106 # include <sys/select.h> /* for FD_ISSET, FD_SET, FD_ZERO */
107 #endif
109 #include <errno.h>
110 #include "_slang.h"
112 #ifdef HAVE_STDLIB_H
113 # include <stdlib.h>
114 #endif
116 #ifdef HAVE_UNISTD_H
117 # include <unistd.h>
118 #endif
120 #if defined(__DECC) && defined(VMS)
121 /* These get prototypes for write an sleep */
122 # include <unixio.h>
123 #endif
124 #include <signal.h>
127 /* Colors: These definitions are used for the display. However, the
128 * application only uses object handles which get mapped to this
129 * internal representation. The mapping is performed by the Color_Map
130 * structure below. */
132 #define CHAR_MASK 0x000000FF
133 #define FG_MASK 0x0000FF00
134 #define BG_MASK 0x00FF0000
135 #define ATTR_MASK 0x1F000000
136 #define BGALL_MASK 0x0FFF0000
138 /* The 0x10000000 bit represents the alternate character set. BGALL_MASK does
139 * not include this attribute.
144 #define GET_FG(color) ((color & FG_MASK) >> 8)
145 #define GET_BG(color) ((color & BG_MASK) >> 16)
146 #define MAKE_COLOR(fg, bg) (((fg) | ((bg) << 8)) << 8)
148 int SLtt_Screen_Cols;
149 int SLtt_Screen_Rows;
150 int SLtt_Term_Cannot_Insert;
151 int SLtt_Term_Cannot_Scroll;
152 int SLtt_Use_Ansi_Colors;
153 int SLtt_Blink_Mode = 1;
154 int SLtt_Use_Blink_For_ACS = 0;
155 int SLtt_Newline_Ok = 0;
156 int SLtt_Has_Alt_Charset = 0;
157 int SLtt_Force_Keypad_Init = 0;
159 /* -1 means unknown */
160 int SLtt_Has_Status_Line = -1; /* hs */
162 static int Automatic_Margins;
163 /* static int No_Move_In_Standout; */
164 static int Worthless_Highlight;
165 #define HP_GLITCH_CODE
166 #ifdef HP_GLITCH_CODE
167 /* This glitch is exclusive to HP term. Basically it means that to clear
168 * attributes, one has to erase to the end of the line.
170 static int Has_HP_Glitch;
171 #endif
173 static char *Reset_Color_String;
175 static int Linux_Console;
177 /* It is crucial that JMAX_COLORS must be less than 128 since the high bit
178 * is used to indicate a character from the ACS (alt char set). The exception
179 * to this rule is if SLtt_Use_Blink_For_ACS is true. This means that of
180 * the highbit is set, we interpret that as a blink character. This is
181 * exploited by DOSemu.
183 #define JMAX_COLORS 256
184 #define JNORMAL_COLOR 0
186 typedef struct
188 SLtt_Char_Type fgbg;
189 SLtt_Char_Type mono;
190 char *custom_esc;
191 } Ansi_Color_Type;
193 #define RGB1(r, g, b) ((r) | ((g) << 1) | ((b) << 2))
194 #define RGB(r, g, b, br, bg, bb) ((RGB1(r, g, b) << 8) | (RGB1(br, bg, bb) << 16))
196 static Ansi_Color_Type Ansi_Color_Map[JMAX_COLORS] =
198 {RGB(1, 1, 1, 0, 0, 0), 0x00000000, NULL}, /* white/black */
199 {RGB(0, 1, 0, 0, 0, 0), SLTT_REV_MASK, NULL}, /* green/black */
200 {RGB(1, 0, 1, 0, 0, 0), SLTT_REV_MASK, NULL}, /* magenta/black */
201 {RGB(0, 1, 1, 0, 0, 0), SLTT_REV_MASK, NULL}, /* cyan/black */
202 {RGB(1, 0, 0, 0, 0, 0), SLTT_REV_MASK, NULL},
203 {RGB(0, 1, 0, 0, 0, 1), SLTT_REV_MASK, NULL},
204 {RGB(1, 0, 0, 0, 0, 1), SLTT_REV_MASK, NULL},
205 {RGB(1, 0, 0, 0, 1, 0), SLTT_REV_MASK, NULL},
206 {RGB(0, 0, 1, 1, 0, 0), SLTT_REV_MASK, NULL},
207 {RGB(0, 1, 0, 1, 0, 0), SLTT_REV_MASK, NULL},
208 {RGB(0, 1, 1, 1, 1, 1), SLTT_REV_MASK, NULL},
209 {RGB(1, 1, 0, 1, 1, 1), SLTT_REV_MASK, NULL},
210 {RGB(1, 0, 1, 1, 1, 1), SLTT_REV_MASK, NULL},
211 {RGB(0, 0, 0, 0, 1, 1), SLTT_REV_MASK, NULL},
212 {RGB(0, 1, 0, 1, 1, 1), SLTT_REV_MASK, NULL},
213 {RGB(0, 1, 0, 1, 1, 1), SLTT_REV_MASK, NULL},
214 {RGB(0, 1, 0, 1, 1, 1), SLTT_REV_MASK, NULL},
215 {RGB(0, 1, 0, 1, 1, 1), SLTT_REV_MASK, NULL}
219 /* This is the string to use to use when outputting color information.
221 #ifdef M_UNIX
222 /* work around for sco console bug that can't handle combined sequences */
223 static char *Color_Escape_Sequence = "\033[3%dm\033[4%dm";
224 #else
225 /* Believe it or not, this is what is in the linux terminfo database. It
226 * produces the same escape sequence but it is much more CPU intensive.
227 * Why not just encode it as "\033[3%p1%dm\033[4%p2%dm" ???
229 /* static char *Color_Escape_Sequence = "\033[%p1%{30}%+%dm\033[%p2%{40}%+%dm"; */
230 static char *Color_Escape_Sequence = "\033[3%d;4%dm";
231 #endif
233 char *SLtt_Graphics_Char_Pairs; /* ac termcap string -- def is vt100 */
236 /* 1 if terminal lacks the ability to do into insert mode or into delete
237 mode. Currently controlled by S-Lang but later perhaps termcap. */
239 static char *UnderLine_Vid_Str;
240 static char *Blink_Vid_Str;
241 static char *Bold_Vid_Str;
242 static char *Ins_Mode_Str; /* = "\033[4h"; */ /* ins mode (im) */
243 static char *Eins_Mode_Str; /* = "\033[4l"; */ /* end ins mode (ei) */
244 static char *Scroll_R_Str; /* = "\033[%d;%dr"; */ /* scroll region */
245 static char *Cls_Str; /* = "\033[2J\033[H"; */ /* cl termcap STR for ansi terminals */
246 static char *Rev_Vid_Str; /* = "\033[7m"; */ /* mr,so termcap string */
247 static char *Norm_Vid_Str; /* = "\033[m"; */ /* me,se termcap string */
248 static char *Del_Eol_Str; /* = "\033[K"; */ /* ce */
249 static char *Del_Char_Str; /* = "\033[P"; */ /* dc */
250 static char *Del_N_Lines_Str; /* = "\033[%dM"; */ /* DL */
251 static char *Add_N_Lines_Str; /* = "\033[%dL"; */ /* AL */
252 static char *Rev_Scroll_Str;
253 static char *Curs_Up_Str;
254 static char *Curs_F_Str; /* RI termcap string */
255 static char *Cursor_Visible_Str; /* ve termcap string */
256 static char *Cursor_Invisible_Str; /* vi termcap string */
258 static char *Start_Alt_Chars_Str; /* as */
259 static char *End_Alt_Chars_Str; /* ae */
260 static char *Enable_Alt_Char_Set; /* eA */
262 static char *Term_Init_Str;
263 static char *Keypad_Init_Str;
264 static char *Term_Reset_Str;
265 static char *Keypad_Reset_Str;
267 /* status line functions */
268 static char *Disable_Status_line_Str; /* ds */
269 static char *Return_From_Status_Line_Str; /* fs */
270 static char *Goto_Status_Line_Str; /* ts */
271 static int Num_Status_Line_Columns; /* ws */
272 static int Status_Line_Esc_Ok; /* es */
274 /* static int Len_Curs_F_Str = 5; */
276 /* cm string has %i%d since termcap numbers columns from 0 */
277 /* char *CURS_POS_STR = "\033[%d;%df"; ansi-- hor and vert pos */
278 static char *Curs_Pos_Str; /* = "\033[%i%d;%dH";*/ /* cm termcap string */
281 /* scrolling region */
282 static int Scroll_r1 = 0, Scroll_r2 = 23;
283 static int Cursor_r, Cursor_c; /* 0 based */
285 /* current attributes --- initialized to impossible value */
286 static SLtt_Char_Type Current_Fgbg = 0xFFFFFFFFU;
288 static int Cursor_Set; /* 1 if cursor position known, 0
289 * if not. -1 if only row is known
293 #define MAX_OUTPUT_BUFFER_SIZE 4096
295 static unsigned char Output_Buffer[MAX_OUTPUT_BUFFER_SIZE];
296 static unsigned char *Output_Bufferp = Output_Buffer;
298 unsigned long SLtt_Num_Chars_Output;
300 #ifdef SLTT_TRANSP_ACS_PATCH
301 static int SLtt_ACS_Active = 0;
302 #endif
304 static int sl_usleep (unsigned long usecs)
306 #ifndef VMS
307 struct timeval tv;
308 tv.tv_sec = usecs / 1000000;
309 tv.tv_usec = usecs % 1000000;
310 return select(0, NULL, NULL, NULL, &tv);
311 #else
312 return 0;
313 #endif
316 int SLtt_flush_output (void)
318 int nwrite = 0;
319 unsigned int total;
320 int n = (int) (Output_Bufferp - Output_Buffer);
322 SLtt_Num_Chars_Output += n;
324 total = 0;
325 while (n > 0)
327 nwrite = write (fileno(stdout), (char *) Output_Buffer + total, n);
328 if (nwrite == -1)
330 nwrite = 0;
331 #ifdef EAGAIN
332 if (errno == EAGAIN)
334 sl_usleep (100000); /* 1/10 sec */
335 continue;
337 #endif
338 #ifdef EWOULDBLOCK
339 if (errno == EWOULDBLOCK)
341 sl_usleep (100000);
342 continue;
344 #endif
345 #ifdef EINTR
346 if (errno == EINTR) continue;
347 #endif
348 break;
350 n -= nwrite;
351 total += nwrite;
353 Output_Bufferp = Output_Buffer;
354 return n;
358 int SLtt_Baud_Rate;
359 static void tt_write(char *str, unsigned int n)
361 static unsigned long last_time;
362 static int total;
363 unsigned long now;
364 unsigned int ndiff;
366 if ((str == NULL) || (n == 0)) return;
367 total += n;
369 while (1)
371 ndiff = MAX_OUTPUT_BUFFER_SIZE - (int) (Output_Bufferp - Output_Buffer);
372 if (ndiff < n)
374 SLMEMCPY ((char *) Output_Bufferp, (char *) str, ndiff);
375 Output_Bufferp += ndiff;
376 SLtt_flush_output ();
377 n -= ndiff;
378 str += ndiff;
380 else
382 SLMEMCPY ((char *) Output_Bufferp, str, n);
383 Output_Bufferp += n;
384 break;
388 if (((SLtt_Baud_Rate > 150) && (SLtt_Baud_Rate <= 9600))
389 && (10 * total > SLtt_Baud_Rate))
391 total = 0;
392 if ((now = (unsigned long) time(NULL)) - last_time <= 1)
394 SLtt_flush_output ();
395 sleep((unsigned) 1);
397 last_time = now;
402 void SLtt_write_string (char *str)
404 if (str != NULL) tt_write(str, strlen(str));
408 void SLtt_putchar (char ch)
410 #ifdef SLTT_TRANSP_ACS_PATCH
411 int restore_acs = 0;
412 #endif
414 SLtt_normal_video ();
415 if (Cursor_Set == 1)
417 if (ch >= ' ') Cursor_c++;
418 #ifndef SLTT_TRANSP_ACS_PATCH
419 else if (ch == '\b') Cursor_c--;
420 #else
421 if (ch <= ' ' && SLtt_ACS_Active)
423 SLtt_set_alt_char_set (0);
424 restore_acs = 1;
426 if (ch == '\b') Cursor_c--;
427 #endif
428 else if (ch == '\r') Cursor_c = 0;
429 else Cursor_Set = 0;
431 if ((Cursor_c + 1 == SLtt_Screen_Cols)
432 && Automatic_Margins) Cursor_Set = 0;
435 if (Output_Bufferp < Output_Buffer + MAX_OUTPUT_BUFFER_SIZE)
437 *Output_Bufferp++ = (unsigned char) ch;
439 else tt_write (&ch, 1);
441 #ifdef SLTT_TRANSP_ACS_PATCH
442 if (restore_acs)
444 SLtt_set_alt_char_set (1);
446 #endif
449 /* this is supposed to be fast--- also handles
450 termcap: %d, &i, %., %+, %r strings as well as terminfo stuff */
451 static unsigned int tt_sprintf(char *buf, char *fmt, int x, int y)
453 register unsigned char *f = (unsigned char *) fmt, *b, ch;
454 int offset = 0, tinfo = 0;
455 int stack[10];
456 int i = 0, z;
457 stack[0] = y; stack[1] = x; i = 2;
459 b = (unsigned char *) buf;
460 if (fmt != NULL) while ((ch = *f++) != 0)
462 if (ch != '%') *b++ = ch;
463 else
465 ch = *f++;
466 if (tinfo)
468 if ((ch <= '3') && (ch >= '0'))
470 /* map it to termcap. Since this is terminfo,
471 * it must be one of:
472 * %2d, %3d, %02d, %03d
474 * I am assuming that a terminal that understands
475 * %2d form will also understand the %02d form. These
476 * only differ by a space padding the field.
479 /* skip the 'd'-- hope it is there */
480 if (ch == '0')
482 ch = *f;
483 f += 2;
485 else f++;
489 switch (ch)
491 case 'p':
492 tinfo = 1;
493 ch = *f++;
494 if (ch == '1') stack[i++] = x; else stack[i++] = y;
495 break;
497 case '\'': /* 'x' */
498 stack[i++] = *f++;
499 f++;
500 break;
502 case '{': /* literal constant, e.g. {30} */
503 z = 0;
504 while (((ch = *f) <= '9') && (ch >= '0'))
506 z = z * 10 + (ch - '0');
507 f++;
509 stack[i++] = z;
510 if (ch == '}') f++;
511 break;
513 case 'd':
514 case '2':
515 case '3':
516 z = stack[--i];
517 z += offset;
518 if (z >= 100)
520 *b++ = z / 100 + '0';
521 z = z % 100;
522 goto ten;
524 else if (ch == 3)
526 *b++ = '0';
527 ch = '2';
530 if (z >= 10)
532 ten:
533 *b++ = z / 10 + '0';
534 z = z % 10;
536 else if (ch == 2) *b++ = '0';
538 *b++ = z + '0';
539 break;
541 case 'i':
542 offset = 1;
543 break;
545 case '+':
546 if (tinfo)
548 z = stack[--i];
549 stack[i-1] += z;
551 else
553 ch = *f++;
554 if ((unsigned char) ch == 128) ch = 0;
555 ch = ch + (unsigned char) stack[--i];
556 if (ch == '\n') ch++;
557 *b++ = ch;
559 break;
561 case 'r':
562 stack[0] = x;
563 stack[1] = y;
564 break;
566 case '.':
567 case 'c':
568 ch = (unsigned char) stack[--i];
569 if (ch == '\n') ch++;
570 *b++ = ch;
571 break;
573 default:
574 *b++ = ch;
578 *b = 0;
579 return((unsigned int) (b - (unsigned char *) buf));
582 static void tt_printf(char *fmt, int x, int y)
584 char buf[256];
585 unsigned int n;
586 if (fmt == NULL) return;
587 n = tt_sprintf(buf, fmt, x, y);
588 tt_write(buf, n);
592 void SLtt_set_scroll_region (int r1, int r2)
594 Scroll_r1 = r1;
595 Scroll_r2 = r2;
596 tt_printf (Scroll_R_Str, Scroll_r1, Scroll_r2);
597 Cursor_Set = 0;
600 void SLtt_reset_scroll_region (void)
602 SLtt_set_scroll_region(0, SLtt_Screen_Rows - 1);
605 int SLtt_set_cursor_visibility (int show)
607 if ((Cursor_Visible_Str == NULL) || (Cursor_Invisible_Str == NULL))
608 return -1;
610 SLtt_write_string (show ? Cursor_Visible_Str : Cursor_Invisible_Str);
611 return 0;
615 /* the goto_rc function moves to row relative to scrolling region */
616 void SLtt_goto_rc(int r, int c)
618 char *s = NULL;
619 int n;
620 char buf[6];
621 #ifdef SLTT_TRANSP_ACS_PATCH
622 int check_alt_acs = 0;
623 #endif
625 if (c < 0)
627 c = -c - 1;
628 Cursor_Set = 0;
631 /* if (No_Move_In_Standout && Current_Fgbg) SLtt_normal_video (); */
632 r += Scroll_r1;
634 if ((Cursor_Set > 0) || ((Cursor_Set < 0) && !Automatic_Margins))
636 n = r - Cursor_r;
637 if ((n == -1) && (Cursor_Set > 0) && (Cursor_c == c)
638 && (Curs_Up_Str != NULL))
640 s = Curs_Up_Str;
642 else if ((n >= 0) && (n <= 4))
644 if ((n == 0) && (Cursor_Set == 1)
645 && ((c > 1) || (c == Cursor_c)))
647 if (Cursor_c == c) return;
648 if (Cursor_c == c + 1)
650 s = buf;
651 *s++ = '\b'; *s = 0;
652 s = buf;
653 #ifdef SLTT_TRANSP_ACS_PATCH
654 check_alt_acs = 1;
655 #endif
658 else if (c == 0)
660 s = buf;
661 if ((Cursor_Set != 1) || (Cursor_c != 0)) *s++ = '\r';
662 while (n--) *s++ = '\n';
663 #ifdef VMS
664 /* Need to add this after \n to start a new record. Sheesh. */
665 *s++ = '\r';
666 #endif
667 *s = 0;
668 s = buf;
669 #ifdef SLTT_TRANSP_ACS_PATCH
670 check_alt_acs = 1;
671 #endif
673 /* Will fail on VMS */
674 #ifndef VMS
675 else if (SLtt_Newline_Ok && (Cursor_Set == 1) &&
676 (Cursor_c >= c) && (c + 3 > Cursor_c))
678 s = buf;
679 while (n--) *s++ = '\n';
680 n = Cursor_c - c;
681 while (n--) *s++ = '\b';
682 *s = 0;
683 s = buf;
684 #ifdef SLTT_TRANSP_ACS_PATCH
685 check_alt_acs = 1;
686 #endif
688 #endif
691 #ifndef SLTT_TRANSP_ACS_PATCH
692 if (s != NULL) SLtt_write_string(s);
693 #else
694 if (s != NULL)
696 if (check_alt_acs && SLtt_ACS_Active)
698 SLtt_set_alt_char_set (0);
699 SLtt_write_string(s);
700 SLtt_set_alt_char_set (1);
702 else SLtt_write_string(s);
704 #endif
705 else tt_printf(Curs_Pos_Str, r, c);
706 Cursor_c = c; Cursor_r = r;
707 Cursor_Set = 1;
710 void SLtt_begin_insert (void)
712 SLtt_write_string(Ins_Mode_Str);
715 void SLtt_end_insert (void)
717 SLtt_write_string(Eins_Mode_Str);
720 void SLtt_delete_char (void)
722 SLtt_normal_video ();
723 SLtt_write_string(Del_Char_Str);
726 void SLtt_erase_line (void)
728 SLtt_write_string("\r");
729 Cursor_Set = 1; Cursor_c = 0;
730 SLtt_del_eol();
733 void SLtt_delete_nlines (int n)
735 int r1, curs;
736 char buf[132];
737 #ifdef SLTT_TRANSP_ACS_PATCH
738 int restore_acs = 0;
739 #endif
741 if (n <= 0) return;
742 SLtt_normal_video ();
743 if (Del_N_Lines_Str != NULL) tt_printf(Del_N_Lines_Str,n, 0);
744 else
745 /* get a new terminal */
747 r1 = Scroll_r1;
748 curs = Cursor_r;
749 SLtt_set_scroll_region(curs, Scroll_r2);
750 SLtt_goto_rc(Scroll_r2 - Scroll_r1, 0);
751 #ifdef SLTT_TRANSP_ACS_PATCH
752 if (SLtt_ACS_Active)
754 SLtt_set_alt_char_set (0);
755 restore_acs = 1;
757 #endif
758 SLMEMSET(buf, '\n', (unsigned int) n);
759 tt_write(buf, (unsigned int) n);
760 #ifdef SLTT_TRANSP_ACS_PATCH
761 if (restore_acs) SLtt_set_alt_char_set (1);
762 #endif
763 /* while (n--) tt_putchar('\n'); */
764 SLtt_set_scroll_region(r1, Scroll_r2);
765 SLtt_goto_rc(curs, 0);
769 void SLtt_cls (void)
771 SLtt_normal_video();
772 SLtt_reset_scroll_region ();
773 SLtt_write_string(Cls_Str);
776 void SLtt_reverse_index (int n)
778 if (!n) return;
780 SLtt_normal_video();
781 if (Add_N_Lines_Str != NULL) tt_printf(Add_N_Lines_Str,n, 0);
782 else
784 while(n--) SLtt_write_string(Rev_Scroll_Str);
789 int SLtt_Ignore_Beep = 1;
790 static char *Visible_Bell_Str;
792 void SLtt_beep (void)
794 if (SLtt_Ignore_Beep & 0x1) SLtt_putchar('\007');
796 if (SLtt_Ignore_Beep & 0x2)
798 if (Visible_Bell_Str != NULL) SLtt_write_string (Visible_Bell_Str);
799 #ifdef __linux__
800 else if (Linux_Console)
802 SLtt_write_string ("\033[?5h");
803 SLtt_flush_output ();
804 sl_usleep (50000);
805 SLtt_write_string ("\033[?5l");
807 #endif
809 SLtt_flush_output ();
812 void SLtt_del_eol (void)
814 if (Current_Fgbg != 0xFFFFFFFFU) SLtt_normal_video ();
815 SLtt_write_string(Del_Eol_Str);
818 typedef const struct
820 char *name;
821 SLtt_Char_Type color;
823 Color_Def_Type;
825 #define MAX_COLOR_NAMES 17
826 static Color_Def_Type Color_Defs [MAX_COLOR_NAMES] =
828 {"black", SLSMG_COLOR_BLACK},
829 {"red", SLSMG_COLOR_RED},
830 {"green", SLSMG_COLOR_GREEN},
831 {"brown", SLSMG_COLOR_BROWN},
832 {"blue", SLSMG_COLOR_BLUE},
833 {"magenta", SLSMG_COLOR_MAGENTA},
834 {"cyan", SLSMG_COLOR_CYAN},
835 {"lightgray", SLSMG_COLOR_LGRAY},
836 {"gray", SLSMG_COLOR_GRAY},
837 {"brightred", SLSMG_COLOR_BRIGHT_RED},
838 {"brightgreen", SLSMG_COLOR_BRIGHT_GREEN},
839 {"yellow", SLSMG_COLOR_BRIGHT_BROWN},
840 {"brightblue", SLSMG_COLOR_BRIGHT_BLUE},
841 {"brightmagenta", SLSMG_COLOR_BRIGHT_CYAN},
842 {"brightcyan", SLSMG_COLOR_BRIGHT_MAGENTA},
843 {"white", SLSMG_COLOR_BRIGHT_WHITE},
844 {"default", 25}
848 void SLtt_set_mono (int obj, char *what, SLtt_Char_Type mask)
850 (void) what;
851 if ((obj < 0) || (obj >= JMAX_COLORS))
853 return;
855 Ansi_Color_Map[obj].mono = mask & ATTR_MASK;
858 static char *check_color_for_digit_form (char *color)
860 unsigned int i, ich;
861 char *s = color;
863 i = 0;
864 while ((ich = (int) *s) != 0)
866 if ((ich < '0') || (ich > '9'))
867 return color;
869 i = i * 10 + (ich - '0');
870 s++;
873 if (i < MAX_COLOR_NAMES)
874 color = Color_Defs[i].name;
876 return color;
879 static int get_default_colors (char **fgp, char **bgp)
881 static char fg_buf[16], bg_buf[16], *bg, *fg;
882 static int already_parsed;
883 char *p, *pmax;
885 if (already_parsed == -1)
886 return -1;
888 if (already_parsed)
890 *fgp = fg;
891 *bgp = bg;
892 return 0;
895 already_parsed = -1;
897 bg = getenv ("COLORFGBG");
899 if (bg == NULL)
901 bg = getenv ("DEFAULT_COLORS");
902 if (bg == NULL)
903 return -1;
906 p = fg_buf;
907 pmax = p + (sizeof (fg_buf) - 1);
909 while ((*bg != 0) && (*bg != ';'))
911 if (p < pmax) *p++ = *bg;
912 bg++;
914 *p = 0;
916 if (*bg) bg++;
918 p = bg_buf;
919 pmax = p + (sizeof (bg_buf) - 1);
921 /* Mark suggested allowing for extra spplication specific stuff following
922 * the background color. That is what the check for the semi-colon is for.
924 while ((*bg != 0) && (*bg != ';'))
926 if (p < pmax) *p++ = *bg;
927 bg++;
929 *p = 0;
931 if (!strcmp (fg_buf, "default") || !strcmp(bg_buf, "default"))
933 *fgp = *bgp = fg = bg = "default";
935 else
937 *fgp = fg = check_color_for_digit_form (fg_buf);
938 *bgp = bg = check_color_for_digit_form (bg_buf);
940 already_parsed = 1;
941 return 0;
945 static unsigned char FgBg_Stats[JMAX_COLORS];
947 static int Color_0_Modified = 0;
949 void SLtt_set_color_object (int obj, SLtt_Char_Type attr)
951 char *cust_esc;
953 if ((obj < 0) || (obj >= JMAX_COLORS)) return;
955 cust_esc = Ansi_Color_Map[obj].custom_esc;
956 if (cust_esc != NULL)
958 SLFREE (cust_esc);
959 FgBg_Stats[(Ansi_Color_Map[obj].fgbg >> 8) & 0x7F] -= 1;
960 Ansi_Color_Map[obj].custom_esc = NULL;
963 Ansi_Color_Map[obj].fgbg = attr;
964 if (obj == 0) Color_0_Modified = 1;
967 SLtt_Char_Type SLtt_get_color_object (int obj)
969 if ((obj < 0) || (obj >= JMAX_COLORS)) return 0;
970 return Ansi_Color_Map[obj].fgbg;
974 void SLtt_add_color_attribute (int obj, SLtt_Char_Type attr)
976 if ((obj < 0) || (obj >= JMAX_COLORS)) return;
978 Ansi_Color_Map[obj].fgbg |= (attr & ATTR_MASK);
979 if (obj == 0) Color_0_Modified = 1;
982 static SLtt_Char_Type fb_to_fgbg (SLtt_Char_Type f, SLtt_Char_Type b)
984 SLtt_Char_Type attr = 0;
986 if ((f & 0xF0) == 0)
988 if (f & 0x8) attr = SLTT_BOLD_MASK;
989 f &= 0x7;
991 else f = 9;
993 if ((b & 0xF0) == 0)
995 if (b & 0x8) attr |= SLTT_BLINK_MASK;
996 b &= 0x7;
998 else b = 9;
1000 return ((f << 8) | (b << 16) | attr);
1003 static int make_color_fgbg (char *fg, char *bg, SLtt_Char_Type *fgbg)
1005 SLtt_Char_Type f = 0xFFFFFFFFU, b = 0xFFFFFFFFU;
1006 char *dfg, *dbg;
1007 unsigned int i;
1009 if ((fg != NULL) && (*fg == 0)) fg = NULL;
1010 if ((bg != NULL) && (*bg == 0)) bg = NULL;
1012 if ((fg == NULL) || (bg == NULL))
1014 if (-1 == get_default_colors (&dfg, &dbg))
1015 return -1;
1017 if (fg == NULL) fg = dfg;
1018 if (bg == NULL) bg = dbg;
1021 for (i = 0; i < MAX_COLOR_NAMES; i++)
1023 if (strcmp(fg, Color_Defs[i].name)) continue;
1024 f = Color_Defs[i].color;
1025 break;
1028 for (i = 0; i < MAX_COLOR_NAMES; i++)
1030 if (strcmp(bg, Color_Defs[i].name)) continue;
1031 b = Color_Defs[i].color;
1032 break;
1035 if ((f == 0xFFFFFFFFU) || (b == 0xFFFFFFFFU))
1036 return -1;
1038 *fgbg = fb_to_fgbg (f, b);
1039 return 0;
1042 void SLtt_set_color (int obj, char *what, char *fg, char *bg)
1044 SLtt_Char_Type fgbg;
1046 (void) what;
1047 if ((obj < 0) || (obj >= JMAX_COLORS))
1048 return;
1050 if (-1 != make_color_fgbg (fg, bg, &fgbg))
1051 SLtt_set_color_object (obj, fgbg);
1054 void SLtt_set_color_fgbg (int obj, SLtt_Char_Type f, SLtt_Char_Type b)
1056 SLtt_set_color_object (obj, fb_to_fgbg (f, b));
1059 void SLtt_set_color_esc (int obj, char *esc)
1061 char *cust_esc;
1062 SLtt_Char_Type fgbg = 0;
1063 int i;
1065 if ((obj < 0) || (obj >= JMAX_COLORS))
1067 return;
1070 cust_esc = Ansi_Color_Map[obj].custom_esc;
1071 if (cust_esc != NULL)
1073 SLFREE (cust_esc);
1074 FgBg_Stats[(Ansi_Color_Map[obj].fgbg >> 8) & 0x7F] -= 1;
1077 cust_esc = (char *) SLMALLOC (strlen(esc) + 1);
1078 if (cust_esc != NULL) strcpy (cust_esc, esc);
1080 Ansi_Color_Map[obj].custom_esc = cust_esc;
1081 if (cust_esc == NULL) fgbg = 0;
1082 else
1084 /* The whole point of this is to generate a unique fgbg */
1085 for (i = 0; i < JMAX_COLORS; i++)
1087 if (FgBg_Stats[i] == 0) fgbg = i;
1089 if (obj == i) continue;
1090 if ((Ansi_Color_Map[i].custom_esc) == NULL) continue;
1091 if (!strcmp (Ansi_Color_Map[i].custom_esc, cust_esc))
1093 fgbg = (Ansi_Color_Map[i].fgbg >> 8) & 0x7F;
1094 break;
1097 FgBg_Stats[fgbg] += 1;
1100 fgbg |= 0x80;
1101 Ansi_Color_Map[obj].fgbg = (fgbg | (fgbg << 8)) << 8;
1102 if (obj == 0) Color_0_Modified = 1;
1105 void SLtt_set_alt_char_set (int i)
1107 #ifndef SLTT_TRANSP_ACS_PATCH
1108 static int last_i;
1109 #else
1110 #define last_i SLtt_ACS_Active
1111 #endif
1112 if (SLtt_Has_Alt_Charset == 0) return;
1113 if (i == last_i) return;
1114 SLtt_write_string (i ? Start_Alt_Chars_Str : End_Alt_Chars_Str );
1115 /* if (i) Current_Fgbg |= SLTT_ALTC_MASK;
1116 else Current_Fgbg &= ~SLTT_ALTC_MASK; */
1117 last_i = i;
1118 #ifdef SLTT_TRANSP_ACS_PATCH
1119 #undef last_i
1120 #endif
1123 static void write_attributes (SLtt_Char_Type fgbg)
1125 int bg0, fg0;
1127 if (Worthless_Highlight) return;
1128 if (fgbg == Current_Fgbg) return;
1130 /* Before spitting out colors, fix attributes */
1131 if ((fgbg & ATTR_MASK) != (Current_Fgbg & ATTR_MASK))
1133 if (Current_Fgbg & ATTR_MASK)
1135 SLtt_write_string(Norm_Vid_Str);
1136 /* In case normal video turns off ALL attributes: */
1137 if (fgbg & SLTT_ALTC_MASK)
1138 Current_Fgbg &= ~SLTT_ALTC_MASK;
1139 SLtt_set_alt_char_set (0);
1142 if ((fgbg & SLTT_ALTC_MASK)
1143 != (Current_Fgbg & SLTT_ALTC_MASK))
1145 SLtt_set_alt_char_set ((int) (fgbg & SLTT_ALTC_MASK));
1148 if (fgbg & SLTT_ULINE_MASK) SLtt_write_string (UnderLine_Vid_Str);
1149 if (fgbg & SLTT_BOLD_MASK) SLtt_bold_video ();
1150 if (fgbg & SLTT_REV_MASK) SLtt_write_string (Rev_Vid_Str);
1151 if (fgbg & SLTT_BLINK_MASK)
1153 /* Someday Linux will have a blink mode that set high intensity
1154 * background. Lets be prepared.
1156 if (SLtt_Blink_Mode) SLtt_write_string (Blink_Vid_Str);
1160 if (SLtt_Use_Ansi_Colors)
1162 fg0 = (int) GET_FG(fgbg);
1163 bg0 = (int) GET_BG(fgbg);
1164 tt_printf(Color_Escape_Sequence, fg0, bg0);
1166 Current_Fgbg = fgbg;
1169 static int Video_Initialized;
1171 void SLtt_reverse_video (int color)
1173 SLtt_Char_Type fgbg;
1174 char *esc;
1176 if (Worthless_Highlight) return;
1177 if ((color < 0) || (color >= JMAX_COLORS)) return;
1179 if (Video_Initialized == 0)
1181 if (color == JNORMAL_COLOR)
1183 SLtt_write_string (Norm_Vid_Str);
1185 else SLtt_write_string (Rev_Vid_Str);
1186 Current_Fgbg = 0xFFFFFFFFU;
1187 return;
1190 if (SLtt_Use_Ansi_Colors)
1192 fgbg = Ansi_Color_Map[color].fgbg;
1193 if ((esc = Ansi_Color_Map[color].custom_esc) != NULL)
1195 if (fgbg != Current_Fgbg)
1197 Current_Fgbg = fgbg;
1198 SLtt_write_string (esc);
1199 return;
1203 else fgbg = Ansi_Color_Map[color].mono;
1205 if (fgbg == Current_Fgbg) return;
1206 write_attributes (fgbg);
1212 void SLtt_normal_video (void)
1214 SLtt_reverse_video(JNORMAL_COLOR);
1217 void SLtt_narrow_width (void)
1219 SLtt_write_string("\033[?3l");
1222 void SLtt_wide_width (void)
1224 SLtt_write_string("\033[?3h");
1227 /* Highest bit represents the character set. */
1228 #define COLOR_MASK 0x7F00
1230 #define COLOR_OF(x) (((unsigned int)(x) & COLOR_MASK) >> 8)
1232 #define COLOR_EQS(a, b) \
1233 (Ansi_Color_Map[COLOR_OF(a)].fgbg == Ansi_Color_Map[COLOR_OF(b)].fgbg)
1236 #define COLOR_EQS(a, b) \
1237 (SLtt_Use_Ansi_Colors \
1238 ? (Ansi_Color_Map[COLOR_OF(a)].fgbg == Ansi_Color_Map[COLOR_OF(b)].fgbg)\
1239 : (Ansi_Color_Map[COLOR_OF(a)].mono == Ansi_Color_Map[COLOR_OF(b)].mono))
1242 #define CHAR_EQS(a, b) (((a) == (b))\
1243 || ((((a) & ~COLOR_MASK) == ((b) & ~COLOR_MASK))\
1244 && COLOR_EQS((a), (b))))
1247 /* The whole point of this routine is to prevent writing to the last column
1248 * and last row on terminals with automatic margins.
1250 static void write_string_with_care (char *str)
1252 unsigned int len;
1254 if (str == NULL) return;
1256 len = strlen (str);
1257 if (Automatic_Margins && (Cursor_r + 1 == SLtt_Screen_Rows))
1259 if (len + (unsigned int) Cursor_c >= (unsigned int) SLtt_Screen_Cols)
1261 /* For now, just do not write there. Later, something more
1262 * sophisticated will be implemented.
1264 if (SLtt_Screen_Cols > Cursor_c)
1265 len = SLtt_Screen_Cols - Cursor_c - 1;
1266 else len = 0;
1269 tt_write (str, len);
1272 static void send_attr_str (unsigned short *s)
1274 unsigned char out[256], ch, *p;
1275 register SLtt_Char_Type attr;
1276 register unsigned short sh;
1277 int color, last_color = -1;
1279 p = out;
1280 while (0 != (sh = *s++))
1282 ch = sh & 0xFF;
1283 color = ((int) sh & 0xFF00) >> 8;
1284 #ifdef SLTT_TRANSP_ACS_PATCH
1285 if (ch <= ' ' && (color & 0x80)) color &= ~0x80;
1286 #endif
1287 if (color != last_color)
1289 if (SLtt_Use_Ansi_Colors) attr = Ansi_Color_Map[color & 0x7F].fgbg;
1290 else attr = Ansi_Color_Map[color & 0x7F].mono;
1292 /* sh => color */
1293 if (color & 0x80) /* alternate char set */
1295 if (SLtt_Use_Blink_For_ACS)
1297 if (SLtt_Blink_Mode) attr |= SLTT_BLINK_MASK;
1299 else attr |= SLTT_ALTC_MASK;
1303 if (attr != Current_Fgbg)
1305 #ifndef SLTT_TRANSP_ACS_PATCH
1306 if ((ch != ' ') ||
1307 /* it is a space so only consider it different if it
1308 * has different attributes.
1310 (attr & BGALL_MASK) != (Current_Fgbg & BGALL_MASK))
1311 #endif
1313 if (p != out)
1315 *p = 0;
1316 write_string_with_care ((char *) out);
1317 Cursor_c += (int) (p - out);
1318 p = out;
1321 if (SLtt_Use_Ansi_Colors && (NULL != Ansi_Color_Map[color & 0x7F].custom_esc))
1323 SLtt_write_string (Ansi_Color_Map[color & 0x7F].custom_esc);
1324 /* Just in case the custom escape sequence screwed up
1325 * the alt character set state...
1327 if ((attr & SLTT_ALTC_MASK) != (Current_Fgbg & SLTT_ALTC_MASK))
1328 SLtt_set_alt_char_set ((int) (attr & SLTT_ALTC_MASK));
1329 Current_Fgbg = attr;
1331 else write_attributes (attr);
1333 last_color = color;
1337 *p++ = ch;
1339 *p = 0;
1340 if (p != out) write_string_with_care ((char *) out);
1341 Cursor_c += (int) (p - out);
1344 static void forward_cursor (unsigned int n, int row)
1346 char buf[30];
1349 if (n <= 4)
1351 SLtt_normal_video ();
1352 SLMEMSET (buf, ' ', n);
1353 buf[n] = 0;
1354 write_string_with_care (buf);
1355 Cursor_c += n;
1357 else if (Curs_F_Str != NULL)
1359 Cursor_c += n;
1360 n = tt_sprintf(buf, Curs_F_Str, (int) n, 0);
1361 tt_write(buf, n);
1363 else SLtt_goto_rc (row, (int) (Cursor_c + n));
1367 #define SPACE_CHAR (0x20 | (JNORMAL_COLOR << 8))
1369 void SLtt_smart_puts(unsigned short *neww, unsigned short *oldd, int len, int row)
1371 register unsigned short *p, *q, *qmax, *pmax, *buf;
1372 unsigned short buffer[256];
1373 unsigned int n_spaces;
1374 unsigned short *space_match, *last_buffered_match;
1375 #ifdef HP_GLITCH_CODE
1376 int handle_hp_glitch = 0;
1377 #endif
1379 q = oldd; p = neww;
1380 qmax = oldd + len;
1381 pmax = p + len;
1383 /* Find out where to begin --- while they match, we are ok */
1384 while (1)
1386 if (q == qmax) return;
1387 #if SLANG_HAS_KANJI_SUPPORT
1388 if (*p & 0x80)
1389 { /* new is kanji */
1390 if ((*q & 0x80) && ((q + 1) < qmax))
1391 { /* old is also kanji */
1392 if (((0xFF & *q) != (0xFF & *p))
1393 || ((0xFF & q[1]) != (0xFF & p[1])))
1394 break; /* both kanji, but not match */
1396 else
1397 { /* kanji match ! */
1398 if (!COLOR_EQS(*q, *p)) break;
1399 q++; p++;
1400 if (!COLOR_EQS(*q, *p)) break;
1401 /* really match! */
1402 q++; p++;
1403 continue;
1406 else break; /* old is not kanji */
1408 else
1409 { /* new is not kanji */
1410 if (*q & 0x80) break; /* old is kanji */
1412 #endif
1413 if (!CHAR_EQS(*q, *p)) break;
1414 q++; p++;
1417 /*position the cursor */
1418 SLtt_goto_rc (row, (int) (p - neww));
1420 #ifdef HP_GLITCH_CODE
1421 if (Has_HP_Glitch)
1423 unsigned short *qq = q;
1424 while (qq < qmax)
1426 if (*qq & 0xFF00)
1428 SLtt_normal_video ();
1429 SLtt_del_eol ();
1430 qmax = q;
1431 handle_hp_glitch = 1;
1432 break;
1434 qq++;
1437 #endif
1438 /* Find where the last non-blank character on old/new screen is */
1440 while (qmax > q)
1442 qmax--;
1443 if (!CHAR_EQS(*qmax, SPACE_CHAR))
1445 qmax++;
1446 break;
1450 while (pmax > p)
1452 pmax--;
1453 if (!CHAR_EQS(*pmax, SPACE_CHAR))
1455 pmax++;
1456 break;
1460 last_buffered_match = buf = buffer; /* buffer is empty */
1462 #ifdef HP_GLITCH_CODE
1463 if (handle_hp_glitch)
1465 while (p < pmax)
1467 *buf++ = *p++;
1470 #endif
1472 /* loop using overwrite then skip algorithm until done */
1473 while (1)
1475 /* while they do not match and we do not hit a space, buffer them up */
1476 n_spaces = 0;
1477 while (p < pmax)
1479 if (CHAR_EQS(*q,SPACE_CHAR) && CHAR_EQS(*p, SPACE_CHAR))
1481 /* If *q is not a space, we would have to overwrite it.
1482 * However, if *q is a space, then while *p is also one,
1483 * we only need to skip over the blank field.
1485 space_match = p;
1486 p++; q++;
1487 while ((p < pmax)
1488 && CHAR_EQS(*q,SPACE_CHAR)
1489 && CHAR_EQS(*p, SPACE_CHAR))
1491 p++;
1492 q++;
1494 n_spaces = (unsigned int) (p - space_match);
1495 break;
1497 #if SLANG_HAS_KANJI_SUPPORT
1498 if ((*p & 0x80) && ((p + 1) < pmax))
1499 { /* new is kanji */
1500 if (*q & 0x80)
1501 { /* old is also kanji */
1502 if (((0xFF & *q) != (0xFF & *p))
1503 || ((0xFF & q[1]) != (0xFF & p[1])))
1505 /* both kanji, but not match */
1506 *buf++ = *p++;
1507 *buf++ = *p++;
1508 q += 2;
1509 continue;
1511 else
1512 { /* kanji match ? */
1513 if (!COLOR_EQS(*q, *p) || !COLOR_EQS(*(q+1), *(p+1)))
1515 /* code is match ,but color is diff */
1516 *buf++ = *p++;
1517 *buf++ = *p++;
1518 continue;
1520 /* really match ! */
1521 break;
1524 else
1525 { /* old is not kanji */
1526 *buf++ = *p++;
1527 *buf++ = *p++;
1528 q += 2;
1529 continue;
1532 else
1533 { /* new is not kanji */
1534 if (*q & 0x80)
1535 { /* old is kanji */
1536 *buf++ = *p++;
1537 q++;
1538 continue;
1541 #endif
1543 if (CHAR_EQS(*q, *p)) break;
1544 *buf++ = *p++;
1545 q++;
1547 *buf = 0;
1549 if (buf != buffer) send_attr_str (buffer);
1550 buf = buffer;
1552 if (n_spaces && (p < pmax))
1554 forward_cursor (n_spaces, row);
1557 /* Now we overwrote what we could and cursor is placed at position
1558 * of a possible match of new and old. If this is the case, skip
1559 * some more.
1561 #if !SLANG_HAS_KANJI_SUPPORT
1562 while ((p < pmax) && CHAR_EQS(*p, *q))
1564 *buf++ = *p++;
1565 q++;
1567 #else
1568 /* Kanji */
1569 while (p < pmax)
1571 if ((*p & 0x80) && ((p + 1) < pmax))
1572 { /* new is kanji */
1573 if (*q & 0x80)
1574 { /* old is also kanji */
1575 if (((0xFF & *q) == (0xFF & *p))
1576 && ((0xFF & q[1]) == (0xFF & p[1])))
1578 /* kanji match ? */
1579 if (!COLOR_EQS(*q, *p)
1580 || !COLOR_EQS(q[1], p[1]))
1581 break;
1583 *buf++ = *p++;
1584 q++;
1585 if (p >= pmax)
1587 *buf++ = SPACE_CHAR;
1588 p++;
1589 break;
1591 else
1593 *buf++ = *p++;
1594 q++;
1595 continue;
1598 else break; /* both kanji, but not match */
1600 else break; /* old is not kanji */
1602 else
1603 { /* new is not kanji */
1604 if (*q & 0x80) break; /* old is kanji */
1605 if (!CHAR_EQS(*q, *p)) break;
1606 *buf++ = *p++;
1607 q++;
1610 #endif
1611 last_buffered_match = buf;
1612 if (p >= pmax) break;
1614 /* jump to new position is it is greater than 5 otherwise
1615 * let it sit in the buffer and output it later.
1617 if ((int) (buf - buffer) >= 5)
1619 forward_cursor ((unsigned int) (buf - buffer), row);
1620 last_buffered_match = buf = buffer;
1624 if (buf != buffer)
1626 if (q < qmax)
1628 if ((buf == last_buffered_match)
1629 && ((int) (buf - buffer) >= 5))
1631 forward_cursor ((unsigned int) (buf - buffer), row);
1633 else
1635 *buf = 0;
1636 send_attr_str (buffer);
1640 if (q < qmax) SLtt_del_eol ();
1641 if (Automatic_Margins && (Cursor_c + 1 >= SLtt_Screen_Cols)) Cursor_Set = 0;
1645 static void get_color_info (void)
1647 char *fg, *bg;
1649 SLtt_Use_Ansi_Colors = (NULL != getenv ("COLORTERM"));
1651 if (-1 == get_default_colors (&fg, &bg))
1652 return;
1654 /* Check to see if application has already set them. */
1655 if (Color_0_Modified)
1656 return;
1658 SLtt_set_color (0, NULL, fg, bg);
1659 SLtt_set_color (1, NULL, bg, fg);
1663 /* termcap stuff */
1665 #ifdef __unix__
1667 #ifndef USE_TERMCAP
1668 static char *Tbuf;
1669 static char *Tstr_Buf;
1671 #define tgetstr SLtt_tigetstr
1672 #define tgetent SLtt_tigetent
1673 #define TGETNUM(x) SLtt_tigetnum((x), &Tbuf)
1674 #define TGETFLAG(x) SLtt_tigetflag((x), &Tbuf)
1675 #else
1677 extern char *tgetstr(char *, char **);
1678 extern int tgetent(char *, char *);
1679 extern int tgetnum(char *);
1680 extern int tgetflag(char *);
1681 static char Tstr_Buf[1024];
1682 static char Tbuf[4096];
1683 #define TGETNUM tgetnum
1684 #define TGETFLAG tgetflag
1685 #endif
1687 static char *my_tgetstr(char *what, char **p)
1689 register char *w, *w1;
1690 char *wsave;
1691 what = tgetstr(what, p);
1692 if (what != NULL)
1694 /* Check for AIX brain-damage */
1695 if (*what == '@')
1696 return NULL;
1698 /* lose pad info --- with today's technology, term is a loser if
1699 it is really needed */
1700 while ((*what == '.') ||
1701 ((*what >= '0') && (*what <= '9'))) what++;
1702 if (*what == '*') what++;
1704 /* lose terminfo padding--- looks like $<...> */
1705 w = what;
1706 while (*w) if ((*w++ == '$') && (*w == '<'))
1708 w1 = w - 1;
1709 while (*w && (*w != '>')) w++;
1710 if (*w == 0) break;
1711 w++;
1712 wsave = w1;
1713 while ((*w1++ = *w++) != 0);
1714 w = wsave;
1716 if (*what == 0) what = NULL;
1718 return(what);
1721 char *SLtt_tgetstr (char *s)
1723 #ifdef USE_TERMCAP
1724 static
1725 #endif
1726 char *p = Tstr_Buf;
1727 return my_tgetstr (s, &p);
1730 int SLtt_tgetnum (char *s)
1732 return TGETNUM (s);
1734 int SLtt_tgetflag (char *s)
1736 return TGETFLAG (s);
1740 static int Vt100_Like = 0;
1742 void SLtt_get_terminfo (void)
1744 char *term, *t, ch;
1745 int is_xterm;
1746 int almost_vtxxx;
1748 get_color_info ();
1750 if (NULL == (term = (char *) getenv("TERM")))
1752 SLang_exit_error("TERM environment variable needs set.");
1755 Linux_Console = (!strncmp (term, "linux", 5)
1756 #ifdef linux
1757 || !strncmp(term, "con", 3)
1758 #endif
1761 t = term;
1763 if (strcmp(t, "vt52") && (*t++ == 'v') && (*t++ == 't')
1764 && (ch = *t, (ch >= '1') && (ch <= '9'))) Vt100_Like = 1;
1766 is_xterm = !strncmp (term, "xterm", 5);
1767 almost_vtxxx = (Vt100_Like
1768 || Linux_Console
1769 || is_xterm
1770 || !strcmp (term, "screen"));
1772 #ifndef USE_TERMCAP
1773 if (NULL == (Tbuf = tgetent (term)))
1775 char err_buf[512];
1776 if (almost_vtxxx) /* Special cases. */
1778 int vt102 = 1;
1779 if (!strcmp (term, "vt100")) vt102 = 0;
1780 SLtt_set_term_vtxxx (&vt102);
1781 return;
1783 g_snprintf (err_buf, sizeof (err_buf), "Unknown terminal: %s\n\
1784 Check the TERM environment variable.\n\
1785 Also make sure that the terminal is defined in the terminfo database.\n\
1786 Alternatively, set the TERMCAP environment variable to the desired\n\
1787 termcap entry.", term);
1788 SLang_exit_error(err_buf);
1790 Tstr_Buf = Tbuf;
1791 #else /* USE_TERMCAP */
1792 if (1 != tgetent(Tbuf, term)) SLang_exit_error("Unknown terminal.");
1793 #endif /* NOT USE_TERMCAP */
1795 if ((NULL == (Cls_Str = SLtt_tgetstr("cl")))
1796 || (NULL == (Curs_Pos_Str = SLtt_tgetstr("cm"))))
1798 SLang_exit_error("Terminal not powerful enough for SLang.");
1801 if ((NULL == (Ins_Mode_Str = SLtt_tgetstr("im")))
1802 || ( NULL == (Eins_Mode_Str = SLtt_tgetstr("ei")))
1803 || ( NULL == (Del_Char_Str = SLtt_tgetstr("dc"))))
1804 SLtt_Term_Cannot_Insert = 1;
1806 Visible_Bell_Str = SLtt_tgetstr ("vb");
1807 Curs_Up_Str = SLtt_tgetstr ("up");
1808 Rev_Scroll_Str = SLtt_tgetstr("sr");
1809 Del_N_Lines_Str = SLtt_tgetstr("DL");
1810 Add_N_Lines_Str = SLtt_tgetstr("AL");
1812 /* Actually these are used to initialize terminals that use cursor
1813 * addressing. Hard to believe.
1815 Term_Init_Str = SLtt_tgetstr ("ti");
1816 Term_Reset_Str = SLtt_tgetstr ("te");
1818 /* If I do this for vtxxx terminals, arrow keys start sending ESC O A,
1819 * which I do not want. This is mainly for HP terminals.
1821 if ((almost_vtxxx == 0) || SLtt_Force_Keypad_Init)
1823 Keypad_Init_Str = SLtt_tgetstr ("ks");
1824 Keypad_Reset_Str = SLtt_tgetstr ("ke");
1827 /* Make up for defective termcap/terminfo databases */
1828 if ((Vt100_Like && (term[2] != '1'))
1829 || Linux_Console
1830 || is_xterm
1833 if (Del_N_Lines_Str == NULL) Del_N_Lines_Str = "\033[%dM";
1834 if (Add_N_Lines_Str == NULL) Add_N_Lines_Str = "\033[%dL";
1837 Scroll_R_Str = SLtt_tgetstr("cs");
1839 SLtt_get_screen_size ();
1841 if ((Scroll_R_Str == NULL)
1842 || (((NULL == Del_N_Lines_Str) || (NULL == Add_N_Lines_Str))
1843 && (NULL == Rev_Scroll_Str)))
1845 if (is_xterm
1846 || Linux_Console
1849 /* Defective termcap mode!!!! */
1850 SLtt_set_term_vtxxx (NULL);
1852 else SLtt_Term_Cannot_Scroll = 1;
1855 Del_Eol_Str = SLtt_tgetstr("ce");
1857 Rev_Vid_Str = SLtt_tgetstr("mr");
1858 if (Rev_Vid_Str == NULL) Rev_Vid_Str = SLtt_tgetstr("so");
1860 Bold_Vid_Str = SLtt_tgetstr("md");
1862 /* Although xterm cannot blink, it does display the blinking characters
1863 * as bold ones. Some Rxvt will display the background as high intensity.
1865 if ((NULL == (Blink_Vid_Str = SLtt_tgetstr("mb")))
1866 && is_xterm)
1867 Blink_Vid_Str = "\033[5m";
1869 UnderLine_Vid_Str = SLtt_tgetstr("us");
1871 Start_Alt_Chars_Str = SLtt_tgetstr ("as"); /* smacs */
1872 End_Alt_Chars_Str = SLtt_tgetstr ("ae"); /* rmacs */
1873 Enable_Alt_Char_Set = SLtt_tgetstr ("eA"); /* enacs */
1874 SLtt_Graphics_Char_Pairs = SLtt_tgetstr ("ac");
1876 #ifndef NCURSES_BRAIN_DAMAGE_CONTROL
1877 # define NCURSES_BRAIN_DAMAGE_CONTROL 0
1878 #endif
1880 #if NCURSES_BRAIN_DAMAGE_CONTROL
1881 if (Linux_Console)
1883 # if 0
1884 char *lgcp = "l\332m\300k\277j\331u\264t\303v\301w\302q\304x\263n\053o\176s\137`\004a\260f\370g\361~\011,\020+\021.\031-\030h\261i\0250\333";
1886 SLtt_Graphics_Char_Pairs = lgcp;
1887 Start_Alt_Chars_Str = "\033(B\033)U\016";
1888 End_Alt_Chars_Str = "\033(B\033)0\017";
1889 Enable_Alt_Char_Set = NULL;
1890 # else
1891 char *lgcp = "`\004a\261f\370g\361h\260j\331k\277l\332m\300n\305o\302q\304r\362s_t\303u\264v\301w\302x\263y\371z\372{\373|\374}\375~";
1893 SLtt_Graphics_Char_Pairs = lgcp;
1894 Start_Alt_Chars_Str = "\033[11m";
1895 End_Alt_Chars_Str = "\033[10m";
1896 Enable_Alt_Char_Set = NULL;
1897 # endif
1899 #endif
1901 if (NULL == SLtt_Graphics_Char_Pairs)
1903 /* make up for defective termcap/terminfo */
1904 if (Vt100_Like)
1906 Start_Alt_Chars_Str = "\016";
1907 End_Alt_Chars_Str = "\017";
1908 Enable_Alt_Char_Set = "\033)0";
1912 /* aixterm added by willi */
1913 if (is_xterm || !strncmp (term, "aixterm", 7))
1915 Start_Alt_Chars_Str = "\016";
1916 End_Alt_Chars_Str = "\017";
1917 Enable_Alt_Char_Set = "\033(B\033)0";
1920 if ((SLtt_Graphics_Char_Pairs == NULL) &&
1921 ((Start_Alt_Chars_Str == NULL) || (End_Alt_Chars_Str == NULL)))
1923 SLtt_Has_Alt_Charset = 0;
1924 Enable_Alt_Char_Set = NULL;
1926 else SLtt_Has_Alt_Charset = 1;
1929 /* status line capabilities */
1930 if ((SLtt_Has_Status_Line == -1)
1931 && (0 != (SLtt_Has_Status_Line = TGETFLAG ("hs"))))
1933 Disable_Status_line_Str = SLtt_tgetstr ("ds");
1934 Return_From_Status_Line_Str = SLtt_tgetstr ("fs");
1935 Goto_Status_Line_Str = SLtt_tgetstr ("ts");
1936 Status_Line_Esc_Ok = TGETFLAG("es");
1937 Num_Status_Line_Columns = TGETNUM("ws");
1938 if (Num_Status_Line_Columns < 0) Num_Status_Line_Columns = 0;
1941 if (NULL == (Norm_Vid_Str = SLtt_tgetstr("me")))
1943 Norm_Vid_Str = SLtt_tgetstr("se");
1946 Cursor_Invisible_Str = SLtt_tgetstr("vi");
1947 Cursor_Visible_Str = SLtt_tgetstr("ve");
1949 Curs_F_Str = SLtt_tgetstr("RI");
1951 #if 0
1952 if (NULL != Curs_F_Str)
1954 Len_Curs_F_Str = strlen(Curs_F_Str);
1956 else Len_Curs_F_Str = strlen(Curs_Pos_Str);
1957 #endif
1959 Automatic_Margins = TGETFLAG ("am");
1960 /* No_Move_In_Standout = !TGETFLAG ("ms"); */
1961 #ifdef HP_GLITCH_CODE
1962 Has_HP_Glitch = TGETFLAG ("xs");
1963 #else
1964 Worthless_Highlight = TGETFLAG ("xs");
1965 #endif
1967 if (Worthless_Highlight == 0)
1968 { /* Magic cookie glitch */
1969 Worthless_Highlight = (TGETNUM ("sg") > 0);
1972 if (Worthless_Highlight)
1973 SLtt_Has_Alt_Charset = 0;
1975 /* Check for color information in the termcap. A program should not
1976 * rely on this information being accurate.
1978 if (SLtt_Use_Ansi_Colors == 0)
1980 Reset_Color_String = SLtt_tgetstr ("op");
1982 SLtt_Use_Ansi_Colors = ((NULL != Reset_Color_String)
1983 || (NULL != SLtt_tgetstr ("Sf"))
1984 || (NULL != SLtt_tgetstr ("Sb"))
1985 || (NULL != SLtt_tgetstr ("AF"))
1986 || (NULL != SLtt_tgetstr ("AB"))
1987 || (-1 != SLtt_tgetnum ("Co"))
1988 || (-1 != SLtt_tgetnum ("pa")));
1992 #if defined(__QNX__) && defined(QNX_QANSI_SLANG_COMPAT_ACS)
1994 * Override the alt-char-set handling string in case of a
1995 * QNX/qansi terminal: use the "old style" strings in order
1996 * to be compatible with S-Lang without the SLTT_TRANSP_ACS_PATCH
1997 * code...
1999 if (SLtt_Has_Alt_Charset &&
2000 strncmp(term, "qansi", 5) == 0 &&
2001 Start_Alt_Chars_Str[0] != '\016')
2003 Start_Alt_Chars_Str = "\016"; /* smacs/as (^N) */
2004 End_Alt_Chars_Str = "\017"; /* rmacs/ae (^O) */
2005 SLtt_Graphics_Char_Pairs = /* acsc/ac */
2006 "``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~O\141";
2009 * it would be required to modify the sgr/sa entry also, if it
2010 * would be used (->embedded as/ae sequences)...
2013 #endif /* __QNX__ && QNX_QANSI_SLANG_COMPAT_ACS */
2017 #endif
2018 /* Unix */
2020 /* specific to vtxxx only */
2021 void SLtt_enable_cursor_keys (void)
2023 #ifdef __unix__
2024 if (Vt100_Like)
2025 #endif
2026 SLtt_write_string("\033=\033[?1l");
2029 #ifdef VMS
2030 void SLtt_get_terminfo ()
2032 int zero = 0;
2034 get_color_info ();
2036 SLtt_set_term_vtxxx(&zero);
2037 Start_Alt_Chars_Str = "\016";
2038 End_Alt_Chars_Str = "\017";
2039 SLtt_Has_Alt_Charset = 1;
2040 SLtt_Graphics_Char_Pairs = "aaffgghhjjkkllmmnnooqqssttuuvvwwxx";
2041 Enable_Alt_Char_Set = "\033(B\033)0";
2042 SLtt_get_screen_size ();
2044 #endif
2046 /* This sets term for vt102 terminals it parameter vt100 is 0. If vt100
2047 * is non-zero, set terminal appropriate for a only vt100
2048 * (no add line capability). */
2050 void SLtt_set_term_vtxxx(int *vt100)
2052 Norm_Vid_Str = "\033[m";
2054 Scroll_R_Str = "\033[%i%d;%dr";
2055 Cls_Str = "\033[2J\033[H";
2056 Rev_Vid_Str = "\033[7m";
2057 Bold_Vid_Str = "\033[1m";
2058 Blink_Vid_Str = "\033[5m";
2059 UnderLine_Vid_Str = "\033[4m";
2060 Del_Eol_Str = "\033[K";
2061 Rev_Scroll_Str = "\033M";
2062 Curs_F_Str = "\033[%dC";
2063 /* Len_Curs_F_Str = 5; */
2064 Curs_Pos_Str = "\033[%i%d;%dH";
2065 if ((vt100 == NULL) || (*vt100 == 0))
2067 Ins_Mode_Str = "\033[4h";
2068 Eins_Mode_Str = "\033[4l";
2069 Del_Char_Str = "\033[P";
2070 Del_N_Lines_Str = "\033[%dM";
2071 Add_N_Lines_Str = "\033[%dL";
2072 SLtt_Term_Cannot_Insert = 0;
2074 else
2076 Del_N_Lines_Str = NULL;
2077 Add_N_Lines_Str = NULL;
2078 SLtt_Term_Cannot_Insert = 1;
2080 SLtt_Term_Cannot_Scroll = 0;
2081 /* No_Move_In_Standout = 0; */
2084 void SLtt_init_video (void)
2086 /* send_string_to_term("\033[?6h"); */
2087 /* relative origin mode */
2088 SLtt_write_string (Term_Init_Str);
2089 SLtt_write_string (Keypad_Init_Str);
2090 SLtt_reset_scroll_region();
2091 SLtt_end_insert();
2092 SLtt_write_string (Enable_Alt_Char_Set);
2093 Video_Initialized = 1;
2097 void SLtt_reset_video (void)
2099 SLtt_goto_rc (SLtt_Screen_Rows - 1, 0);
2100 Cursor_Set = 0;
2101 SLtt_normal_video (); /* MSKermit requires this */
2102 SLtt_write_string(Norm_Vid_Str);
2104 Current_Fgbg = 0xFFFFFFFFU;
2105 SLtt_set_alt_char_set (0);
2106 if (SLtt_Use_Ansi_Colors)
2108 if (Reset_Color_String == NULL)
2110 SLtt_Char_Type attr;
2111 if (-1 != make_color_fgbg (NULL, NULL, &attr))
2112 write_attributes (attr);
2113 else SLtt_write_string ("\033[0m\033[m");
2115 else SLtt_write_string (Reset_Color_String);
2116 Current_Fgbg = 0xFFFFFFFFU;
2118 SLtt_erase_line ();
2119 SLtt_write_string (Keypad_Reset_Str);
2120 SLtt_write_string (Term_Reset_Str);
2121 SLtt_flush_output ();
2122 Video_Initialized = 0;
2125 void SLtt_bold_video (void)
2127 SLtt_write_string (Bold_Vid_Str);
2130 int SLtt_set_mouse_mode (int mode, int force)
2132 char *term;
2134 if (force == 0)
2136 if (NULL == (term = (char *) getenv("TERM"))) return -1;
2137 if (strncmp ("xterm", term, 5))
2138 return -1;
2141 if (mode)
2142 SLtt_write_string ("\033[?9h");
2143 else
2144 SLtt_write_string ("\033[?9l");
2146 return 0;
2150 void SLtt_disable_status_line (void)
2152 if (SLtt_Has_Status_Line > 0)
2153 SLtt_write_string (Disable_Status_line_Str);
2156 int SLtt_write_to_status_line (char *s, int col)
2158 if ((SLtt_Has_Status_Line <= 0)
2159 || (Goto_Status_Line_Str == NULL)
2160 || (Return_From_Status_Line_Str == NULL))
2161 return -1;
2163 tt_printf (Goto_Status_Line_Str, col, 0);
2164 SLtt_write_string (s);
2165 SLtt_write_string (Return_From_Status_Line_Str);
2166 return 0;
2170 void SLtt_get_screen_size (void)
2172 #ifdef VMS
2173 int status, code;
2174 unsigned short chan;
2175 $DESCRIPTOR(dev_dsc, "SYS$INPUT:");
2176 #endif
2177 #ifdef __os2__
2178 VIOMODEINFO vioModeInfo;
2179 #endif
2180 int r = 0, c = 0;
2182 #if defined(TIOCGWINSZ) && !defined(SCO_FLAVOR)
2183 struct winsize wind_struct;
2187 if ((ioctl(1,TIOCGWINSZ,&wind_struct) == 0)
2188 || (ioctl(0, TIOCGWINSZ, &wind_struct) == 0)
2189 || (ioctl(2, TIOCGWINSZ, &wind_struct) == 0))
2191 c = (int) wind_struct.ws_col;
2192 r = (int) wind_struct.ws_row;
2193 break;
2196 while (errno == EINTR);
2198 #endif
2200 #ifdef VMS
2201 status = sys$assign(&dev_dsc,&chan,0,0,0);
2202 if (status & 1)
2204 code = DVI$_DEVBUFSIZ;
2205 status = lib$getdvi(&code, &chan,0, &c, 0,0);
2206 if (!(status & 1))
2207 c = 80;
2208 code = DVI$_TT_PAGE;
2209 status = lib$getdvi(&code, &chan,0, &r, 0,0);
2210 if (!(status & 1))
2211 r = 24;
2212 sys$dassgn(chan);
2214 #endif
2216 #ifdef __os2__
2217 vioModeInfo.cb = sizeof(vioModeInfo);
2218 VioGetMode (&vioModeInfo, 0);
2219 c = vioModeInfo.col;
2220 r = vioModeInfo.row;
2221 #endif
2223 if (r <= 0)
2225 char *s = getenv ("LINES");
2226 if (s != NULL) r = atoi (s);
2229 if (c <= 0)
2231 char *s = getenv ("COLUMNS");
2232 if (s != NULL) c = atoi (s);
2235 if ((r <= 0) || (r > 200)) r = 24;
2236 if ((c <= 0) || (c > 250)) c = 80;
2237 SLtt_Screen_Rows = r;
2238 SLtt_Screen_Cols = c;