1 /* Copyright (c) 1992, 1999, 2001, 2002 John E. Davis
2 * This file is part of the S-Lang library.
4 * You may distribute under the terms of either the GNU General Public
5 * License or the Perl Artistic License.
12 #if !defined(VMS) || (__VMS_VER >= 70000000)
13 # include <sys/time.h>
15 # include <sys/select.h>
17 # include <sys/types.h>
21 /* Prototype for select */
22 # include <net/socket.h>
34 # include <lib$routines.h>
38 # include <sys/ioctl.h>
43 # include <sys/termio.h>
44 # include <sys/stream.h>
45 # include <sys/ptem.h>
49 #if defined (_AIX) && !defined (FD_SET)
50 # include <sys/select.h> /* for FD_ISSET, FD_SET, FD_ZERO */
55 #if defined(__DECC) && defined(VMS)
56 /* These get prototypes for write an sleep */
64 /* Colors: These definitions are used for the display. However, the
65 * application only uses object handles which get mapped to this
66 * internal representation. The mapping is performed by the Color_Map
69 #define CHAR_MASK 0x000000FF
70 #define FG_MASK 0x0000FF00
71 #define BG_MASK 0x00FF0000
72 #define ATTR_MASK 0x1F000000
73 #define BGALL_MASK 0x0FFF0000
75 /* The 0x10000000 bit represents the alternate character set. BGALL_MASK does
76 * not include this attribute.
79 #define GET_FG(color) ((color & FG_MASK) >> 8)
80 #define GET_BG(color) ((color & BG_MASK) >> 16)
81 #define MAKE_COLOR(fg, bg) (((fg) | ((bg) << 8)) << 8)
85 int SLtt_Term_Cannot_Insert
;
86 int SLtt_Term_Cannot_Scroll
;
87 int SLtt_Use_Ansi_Colors
;
88 int SLtt_Blink_Mode
= 1;
89 int SLtt_Use_Blink_For_ACS
= 0;
90 int SLtt_Newline_Ok
= 0;
91 int SLtt_Has_Alt_Charset
= 0;
92 int SLtt_Force_Keypad_Init
= 0;
94 void (*_SLtt_color_changed_hook
)(void);
96 #if SLTT_HAS_NON_BCE_SUPPORT
97 static int Bce_Color_Offset
= 0;
99 static int Can_Background_Color_Erase
= 1;
101 /* -1 means unknown */
102 int SLtt_Has_Status_Line
= -1; /* hs */
103 int SLang_TT_Write_FD
= -1;
105 static int Automatic_Margins
;
106 /* static int No_Move_In_Standout; */
107 static int Worthless_Highlight
;
108 #define HP_GLITCH_CODE
109 #ifdef HP_GLITCH_CODE
110 /* This glitch is exclusive to HP term. Basically it means that to clear
111 * attributes, one has to erase to the end of the line.
113 static int Has_HP_Glitch
;
116 static char *Reset_Color_String
;
117 static int Is_Color_Terminal
= 0;
119 static int Linux_Console
;
121 /* It is crucial that JMAX_COLORS must be less than 128 since the high bit
122 * is used to indicate a character from the ACS (alt char set). The exception
123 * to this rule is if SLtt_Use_Blink_For_ACS is true. This means that of
124 * the highbit is set, we interpret that as a blink character. This is
125 * exploited by DOSemu.
127 #define JMAX_COLORS 256
128 #define JNORMAL_COLOR 0
138 #define RGB1(r, g, b) ((r) | ((g) << 1) | ((b) << 2))
139 #define RGB(r, g, b, br, bg, bb) ((RGB1(r, g, b) << 8) | (RGB1(br, bg, bb) << 16))
141 static Ansi_Color_Type Ansi_Color_Map
[JMAX_COLORS
] =
143 {RGB(1, 1, 1, 0, 0, 0), 0x00000000, NULL
}, /* white/black */
144 {RGB(0, 1, 0, 0, 0, 0), SLTT_REV_MASK
, NULL
}, /* green/black */
145 {RGB(1, 0, 1, 0, 0, 0), SLTT_REV_MASK
, NULL
}, /* magenta/black */
146 {RGB(0, 1, 1, 0, 0, 0), SLTT_REV_MASK
, NULL
}, /* cyan/black */
147 {RGB(1, 0, 0, 0, 0, 0), SLTT_REV_MASK
, NULL
},
148 {RGB(0, 1, 0, 0, 0, 1), SLTT_REV_MASK
, NULL
},
149 {RGB(1, 0, 0, 0, 0, 1), SLTT_REV_MASK
, NULL
},
150 {RGB(1, 0, 0, 0, 1, 0), SLTT_REV_MASK
, NULL
},
151 {RGB(0, 0, 1, 1, 0, 0), SLTT_REV_MASK
, NULL
},
152 {RGB(0, 1, 0, 1, 0, 0), SLTT_REV_MASK
, NULL
},
153 {RGB(0, 1, 1, 1, 1, 1), SLTT_REV_MASK
, NULL
},
154 {RGB(1, 1, 0, 1, 1, 1), SLTT_REV_MASK
, NULL
},
155 {RGB(1, 0, 1, 1, 1, 1), SLTT_REV_MASK
, NULL
},
156 {RGB(0, 0, 0, 0, 1, 1), SLTT_REV_MASK
, NULL
},
157 {RGB(0, 1, 0, 1, 1, 1), SLTT_REV_MASK
, NULL
},
158 {RGB(0, 1, 0, 1, 1, 1), SLTT_REV_MASK
, NULL
},
159 {RGB(0, 1, 0, 1, 1, 1), SLTT_REV_MASK
, NULL
},
160 {RGB(0, 1, 0, 1, 1, 1), SLTT_REV_MASK
, NULL
}
163 /* 0 if least significant bit is blue, not red */
164 static int Is_Fg_BGR
= 0;
165 static int Is_Bg_BGR
= 0;
166 #define COLOR_ARG(color, is_bgr) (is_bgr ? RGB_to_BGR[color] : color)
167 static int RGB_to_BGR
[] =
169 0, 4, 2, 6, 1, 5, 3, 7
172 static char *Color_Fg_Str
= "\033[3%dm";
173 static char *Color_Bg_Str
= "\033[4%dm";
174 static char *Default_Color_Fg_Str
= "\033[39m";
175 static char *Default_Color_Bg_Str
= "\033[49m";
177 static int Max_Terminfo_Colors
= 8; /* termcap Co */
179 char *SLtt_Graphics_Char_Pairs
; /* ac termcap string -- def is vt100 */
181 /* 1 if terminal lacks the ability to go into insert mode or into delete
182 mode. Currently controlled by S-Lang but later perhaps termcap. */
184 static char *UnderLine_Vid_Str
;
185 static char *Blink_Vid_Str
;
186 static char *Bold_Vid_Str
;
187 static char *Ins_Mode_Str
; /* = "\033[4h"; */ /* ins mode (im) */
188 static char *Eins_Mode_Str
; /* = "\033[4l"; */ /* end ins mode (ei) */
189 static char *Scroll_R_Str
; /* = "\033[%d;%dr"; */ /* scroll region */
190 static char *Cls_Str
; /* = "\033[2J\033[H"; */ /* cl termcap STR for ansi terminals */
191 static char *Rev_Vid_Str
; /* = "\033[7m"; */ /* mr,so termcap string */
192 static char *Norm_Vid_Str
; /* = "\033[m"; */ /* me,se termcap string */
193 static char *Del_Eol_Str
; /* = "\033[K"; */ /* ce */
194 static char *Del_Bol_Str
; /* = "\033[1K"; */ /* cb */
195 static char *Del_Char_Str
; /* = "\033[P"; */ /* dc */
196 static char *Del_N_Lines_Str
; /* = "\033[%dM"; */ /* DL */
197 static char *Add_N_Lines_Str
; /* = "\033[%dL"; */ /* AL */
198 static char *Rev_Scroll_Str
;
199 static char *Curs_Up_Str
;
200 static char *Curs_F_Str
; /* RI termcap string */
201 static char *Cursor_Visible_Str
; /* ve termcap string */
202 static char *Cursor_Invisible_Str
; /* vi termcap string */
204 static char *Start_Mouse_Rpt_Str
; /* Start mouse reporting mode */
205 static char *End_Mouse_Rpt_Str
; /* End mouse reporting mode */
207 static char *Start_Alt_Chars_Str
; /* as */
208 static char *End_Alt_Chars_Str
; /* ae */
209 static char *Enable_Alt_Char_Set
; /* eA */
211 static char *Term_Init_Str
;
212 static char *Keypad_Init_Str
;
213 static char *Term_Reset_Str
;
214 static char *Keypad_Reset_Str
;
216 /* status line functions */
217 static char *Disable_Status_line_Str
; /* ds */
218 static char *Return_From_Status_Line_Str
; /* fs */
219 static char *Goto_Status_Line_Str
; /* ts */
220 static int Num_Status_Line_Columns
; /* ws */
221 /* static int Status_Line_Esc_Ok; */ /* es */
223 /* static int Len_Curs_F_Str = 5; */
225 /* cm string has %i%d since termcap numbers columns from 0 */
226 /* char *CURS_POS_STR = "\033[%d;%df"; ansi-- hor and vert pos */
227 static char *Curs_Pos_Str
; /* = "\033[%i%d;%dH";*/ /* cm termcap string */
229 /* scrolling region */
230 static int Scroll_r1
= 0, Scroll_r2
= 23;
231 static int Cursor_r
, Cursor_c
; /* 0 based */
233 /* current attributes --- initialized to impossible value */
234 static SLtt_Char_Type Current_Fgbg
= 0xFFFFFFFFU
;
236 static int Cursor_Set
; /* 1 if cursor position known, 0
237 * if not. -1 if only row is known
240 #define MAX_OUTPUT_BUFFER_SIZE 4096
242 static unsigned char Output_Buffer
[MAX_OUTPUT_BUFFER_SIZE
];
243 static unsigned char *Output_Bufferp
= Output_Buffer
;
245 unsigned long SLtt_Num_Chars_Output
;
247 int _SLusleep (unsigned long usecs
)
249 #if !defined(VMS) || (__VMS_VER >= 70000000)
251 tv
.tv_sec
= usecs
/ 1000000;
252 tv
.tv_usec
= usecs
% 1000000;
253 return select(0, NULL
, NULL
, NULL
, &tv
);
259 int SLtt_flush_output (void)
263 int n
= (int) (Output_Bufferp
- Output_Buffer
);
265 SLtt_Num_Chars_Output
+= n
;
270 nwrite
= write (SLang_TT_Write_FD
, (char *) Output_Buffer
+ total
, n
);
277 _SLusleep (100000); /* 1/10 sec */
282 if (errno
== EWOULDBLOCK
)
289 if (errno
== EINTR
) continue;
296 Output_Bufferp
= Output_Buffer
;
301 static void tt_write(char *str
, unsigned int n
)
303 static unsigned long last_time
;
308 if ((str
== NULL
) || (n
== 0)) return;
313 ndiff
= MAX_OUTPUT_BUFFER_SIZE
- (int) (Output_Bufferp
- Output_Buffer
);
316 SLMEMCPY ((char *) Output_Bufferp
, (char *) str
, ndiff
);
317 Output_Bufferp
+= ndiff
;
318 SLtt_flush_output ();
324 SLMEMCPY ((char *) Output_Bufferp
, str
, n
);
330 if (((SLtt_Baud_Rate
> 150) && (SLtt_Baud_Rate
<= 9600))
331 && (10 * total
> SLtt_Baud_Rate
))
334 if ((now
= (unsigned long) time(NULL
)) - last_time
<= 1)
336 SLtt_flush_output ();
343 static void tt_write_string (char *str
)
345 if (str
!= NULL
) tt_write(str
, strlen(str
));
348 void SLtt_write_string (char *str
)
350 tt_write_string (str
);
354 void SLtt_putchar (char ch
)
356 SLtt_normal_video ();
359 if (ch
>= ' ') Cursor_c
++;
360 else if (ch
== '\b') Cursor_c
--;
361 else if (ch
== '\r') Cursor_c
= 0;
364 if ((Cursor_c
+ 1 == SLtt_Screen_Cols
)
365 && Automatic_Margins
) Cursor_Set
= 0;
368 if (Output_Bufferp
< Output_Buffer
+ MAX_OUTPUT_BUFFER_SIZE
)
370 *Output_Bufferp
++ = (unsigned char) ch
;
372 else tt_write (&ch
, 1);
375 static unsigned int tt_sprintf(char *buf
, char *fmt
, int x
, int y
)
378 register unsigned char *b
, ch
;
380 int z
, z1
, parse_level
;
385 unsigned int stack_len
;
387 #define STACK_POP (stack_len ? stack[--stack_len] : 0)
395 stack
[0] = y
; /* pushed for termcap */
399 parms
[1] = x
; /* p1 */
400 parms
[2] = y
; /* p2 */
406 b
= (unsigned char *) buf
;
407 fmt_max
= fmt
+ strlen (fmt
);
409 while (fmt
< fmt_max
)
419 if (fmt
== fmt_max
) break;
430 if (fmt
== fmt_max
) break;
432 if ((ch
>= '0') && (ch
<= '9'))
433 stack
[stack_len
++] = parms
[ch
- '0'];
437 if (fmt
== fmt_max
) break;
438 stack
[stack_len
++] = *fmt
++;
439 if (fmt
< fmt_max
) fmt
++; /* skip ' */
442 case '{': /* literal constant, e.g. {30} */
444 while ((fmt
< fmt_max
) && ((ch
= *fmt
) <= '9') && (ch
>= '0'))
446 z
= z
* 10 + (ch
- '0');
449 stack
[stack_len
++] = z
;
450 if ((ch
== '}') && (fmt
< fmt_max
)) fmt
++;
454 if (fmt
== fmt_max
) break;
456 if ((ch
!= '2') && (ch
!= '3'))
470 x_fmt_buf_ptr
= x_fmt_buf
;
471 if (zero_pad
) *x_fmt_buf_ptr
++ = '0';
472 *x_fmt_buf_ptr
++ = ch
;
473 *x_fmt_buf_ptr
++ = 'X';
479 sprintf ((char *)b
, x_fmt_buf
, z
);
480 b
+= strlen ((char *)b
);
485 field_width
= (ch
- '0');
493 *b
++ = z
/ 100 + '0';
498 else if (zero_pad
&& (field_width
== 3))
506 else if (zero_pad
&& (field_width
>= 2))
510 field_width
= zero_pad
= 0;
516 sprintf ((char *) b
, "%X", z
);
517 b
+= strlen ((char *)b
);
525 /* Handling this depends upon whether or not we are parsing
526 * terminfo. Terminfo requires the stack so use it as an
532 stack
[stack_len
- 1] += z
;
534 else if (fmt
< fmt_max
)
537 if ((unsigned char) ch
== 128) ch
= 0;
538 ch
= ch
+ (unsigned char) STACK_POP
;
539 if (ch
== '\n') ch
++;
544 /* Binary operators */
561 case '-': z
= (z
- z1
); break;
562 case '*': z
= (z
* z1
); break;
563 case '/': z
= (z
/ z1
); break;
564 case 'm': z
= (z
% z1
); break;
565 case '&': z
= (z
& z1
); break;
566 case '|': z
= (z
| z1
); break;
567 case '^': z
= (z
^ z1
); break;
568 case '=': z
= (z
== z1
); break;
569 case '>': z
= (z
> z1
); break;
570 case '<': z
= (z
< z1
); break;
571 case 'A': z
= (z
&& z1
); break;
572 case 'O': z
= (z
|| z1
); break;
574 stack
[stack_len
++] = z
;
580 stack
[stack_len
++] = !z
;
585 stack
[stack_len
++] = ~z
;
588 case 'r': /* termcap -- swap parameters */
590 stack
[0] = stack
[1];
594 case '.': /* termcap */
596 ch
= (unsigned char) STACK_POP
;
597 if (ch
== '\n') ch
++;
602 if (fmt
== fmt_max
) break;
604 if ((ch
>= 'a') && (ch
<= 'z'))
605 stack
[stack_len
++] = variables
[ch
- 'a'];
609 if (fmt
== fmt_max
) break;
611 if ((ch
>= 'a') && (ch
<= 'z'))
612 variables
[ch
- 'a'] = STACK_POP
;
615 /* If then else parsing. Actually, this is rather easy. The
616 * key is to notice that 'then' does all the work. 'if' simply
617 * there to indicate the start of a test and endif indicates
618 * the end of tests. If 'else' is seen, then skip to
622 case ';': /* endif */
628 break; /* good. Continue parsing. */
630 /* z == 0 and test has failed. So, skip past this entire if
631 * expression to the matching else or matching endif.
637 while (fmt
< fmt_max
)
642 if ((ch1
!= '%') || (fmt
== fmt_max
))
647 if (ch1
== '?') parse_level
++; /* new if */
650 if ((ch
!= 'e') && (parse_level
== 0))
655 if (parse_level
== 0)
664 return (unsigned int) (b
- (unsigned char *) buf
);
667 static void tt_printf(char *fmt
, int x
, int y
)
671 if (fmt
== NULL
) return;
672 n
= tt_sprintf(buf
, fmt
, x
, y
);
676 void SLtt_set_scroll_region (int r1
, int r2
)
680 tt_printf (Scroll_R_Str
, Scroll_r1
, Scroll_r2
);
684 void SLtt_reset_scroll_region (void)
686 SLtt_set_scroll_region(0, SLtt_Screen_Rows
- 1);
689 int SLtt_set_cursor_visibility (int show
)
691 if ((Cursor_Visible_Str
== NULL
) || (Cursor_Invisible_Str
== NULL
))
694 tt_write_string (show
? Cursor_Visible_Str
: Cursor_Invisible_Str
);
698 /* the goto_rc function moves to row relative to scrolling region */
699 void SLtt_goto_rc(int r
, int c
)
705 if ((c
< 0) || (r
< 0))
711 /* if (No_Move_In_Standout && Current_Fgbg) SLtt_normal_video (); */
714 if ((Cursor_Set
> 0) || ((Cursor_Set
< 0) && !Automatic_Margins
))
717 if ((n
== -1) && (Cursor_Set
> 0) && (Cursor_c
== c
)
718 && (Curs_Up_Str
!= NULL
))
722 else if ((n
>= 0) && (n
<= 4))
724 if ((n
== 0) && (Cursor_Set
== 1)
725 && ((c
> 1) || (c
== Cursor_c
)))
727 if (Cursor_c
== c
) return;
728 if (Cursor_c
== c
+ 1)
738 if ((Cursor_Set
!= 1) || (Cursor_c
!= 0)) *s
++ = '\r';
739 while (n
--) *s
++ = '\n';
741 /* Need to add this after \n to start a new record. Sheesh. */
747 /* Will fail on VMS */
749 else if (SLtt_Newline_Ok
&& (Cursor_Set
== 1) &&
750 (Cursor_c
>= c
) && (c
+ 3 > Cursor_c
))
753 while (n
--) *s
++ = '\n';
755 while (n
--) *s
++ = '\b';
762 if (s
!= NULL
) tt_write_string(s
);
763 else tt_printf(Curs_Pos_Str
, r
, c
);
764 Cursor_c
= c
; Cursor_r
= r
;
768 void SLtt_begin_insert (void)
770 tt_write_string(Ins_Mode_Str
);
773 void SLtt_end_insert (void)
775 tt_write_string(Eins_Mode_Str
);
778 void SLtt_delete_char (void)
780 SLtt_normal_video ();
781 tt_write_string(Del_Char_Str
);
784 void SLtt_erase_line (void)
786 tt_write_string("\r");
787 Cursor_Set
= 1; Cursor_c
= 0;
791 /* It appears that the Linux console, and most likely others do not
792 * like scrolling regions that consist of one line. So I have to
793 * resort to this stupidity to make up for that stupidity.
795 static void delete_line_in_scroll_region (void)
797 SLtt_goto_rc (Cursor_r
- Scroll_r1
, 0);
801 void SLtt_delete_nlines (int n
)
807 SLtt_normal_video ();
809 if (Scroll_r1
== Scroll_r2
)
811 delete_line_in_scroll_region ();
815 if (Del_N_Lines_Str
!= NULL
) tt_printf(Del_N_Lines_Str
,n
, 0);
817 /* get a new terminal */
821 SLtt_set_scroll_region(curs
, Scroll_r2
);
822 SLtt_goto_rc(Scroll_r2
- Scroll_r1
, 0);
823 SLMEMSET(buf
, '\n', (unsigned int) n
);
824 tt_write(buf
, (unsigned int) n
);
825 /* while (n--) tt_putchar('\n'); */
826 SLtt_set_scroll_region(r1
, Scroll_r2
);
827 SLtt_goto_rc(curs
, 0);
833 /* If the terminal is a color terminal but the user wants black and
834 * white, then make sure that the colors are reset. This appears to be
837 if ((SLtt_Use_Ansi_Colors
== 0) && Is_Color_Terminal
)
839 if (Reset_Color_String
!= NULL
)
840 tt_write_string (Reset_Color_String
);
842 tt_write_string ("\033[0m\033[m");
846 SLtt_reset_scroll_region ();
847 tt_write_string(Cls_Str
);
850 void SLtt_reverse_index (int n
)
856 if (Scroll_r1
== Scroll_r2
)
858 delete_line_in_scroll_region ();
862 if (Add_N_Lines_Str
!= NULL
) tt_printf(Add_N_Lines_Str
,n
, 0);
865 while(n
--) tt_write_string(Rev_Scroll_Str
);
869 int SLtt_Ignore_Beep
= 1;
870 static char *Visible_Bell_Str
;
872 void SLtt_beep (void)
874 if (SLtt_Ignore_Beep
& 0x1) SLtt_putchar('\007');
876 if (SLtt_Ignore_Beep
& 0x2)
878 if (Visible_Bell_Str
!= NULL
) tt_write_string (Visible_Bell_Str
);
880 else if (Linux_Console
)
882 tt_write_string ("\033[?5h");
883 SLtt_flush_output ();
885 tt_write_string ("\033[?5l");
889 SLtt_flush_output ();
892 static void del_eol (void)
896 if (Del_Eol_Str
!= NULL
)
898 tt_write_string(Del_Eol_Str
);
903 /* Avoid writing to the lower right corner. If the terminal does not
904 * have Del_Eol_Str, then it probably does not have what it takes to play
905 * games with insert for for a space into that corner.
907 if (Cursor_r
+ 1 < SLtt_Screen_Rows
)
910 while (c
< SLtt_Screen_Cols
)
917 void SLtt_del_eol (void)
919 if (Current_Fgbg
!= 0xFFFFFFFFU
) SLtt_normal_video ();
926 SLtt_Char_Type color
;
930 #define MAX_COLOR_NAMES 17
931 static Color_Def_Type Color_Defs
[MAX_COLOR_NAMES
] =
933 {"black", SLSMG_COLOR_BLACK
},
934 {"red", SLSMG_COLOR_RED
},
935 {"green", SLSMG_COLOR_GREEN
},
936 {"brown", SLSMG_COLOR_BROWN
},
937 {"blue", SLSMG_COLOR_BLUE
},
938 {"magenta", SLSMG_COLOR_MAGENTA
},
939 {"cyan", SLSMG_COLOR_CYAN
},
940 {"lightgray", SLSMG_COLOR_LGRAY
},
941 {"gray", SLSMG_COLOR_GRAY
},
942 {"brightred", SLSMG_COLOR_BRIGHT_RED
},
943 {"brightgreen", SLSMG_COLOR_BRIGHT_GREEN
},
944 {"yellow", SLSMG_COLOR_BRIGHT_BROWN
},
945 {"brightblue", SLSMG_COLOR_BRIGHT_BLUE
},
946 {"brightmagenta", SLSMG_COLOR_BRIGHT_CYAN
},
947 {"brightcyan", SLSMG_COLOR_BRIGHT_MAGENTA
},
948 {"white", SLSMG_COLOR_BRIGHT_WHITE
},
949 #define SLSMG_COLOR_DEFAULT 0xFF
950 {"default", SLSMG_COLOR_DEFAULT
}
953 void SLtt_set_mono (int obj
, char *what
, SLtt_Char_Type mask
)
956 if ((obj
< 0) || (obj
>= JMAX_COLORS
))
960 Ansi_Color_Map
[obj
].mono
= mask
& ATTR_MASK
;
963 static char *check_color_for_digit_form (char *color
)
969 while ((ich
= (int) *s
) != 0)
971 if ((ich
< '0') || (ich
> '9'))
974 i
= i
* 10 + (ich
- '0');
978 if (i
< MAX_COLOR_NAMES
)
979 color
= Color_Defs
[i
].name
;
984 static int get_default_colors (char **fgp
, char **bgp
)
986 static char fg_buf
[16], bg_buf
[16], *bg
, *fg
;
987 static int already_parsed
;
990 if (already_parsed
== -1)
1000 already_parsed
= -1;
1002 bg
= getenv ("COLORFGBG");
1006 bg
= getenv ("DEFAULT_COLORS");
1012 pmax
= p
+ (sizeof (fg_buf
) - 1);
1014 while ((*bg
!= 0) && (*bg
!= ';'))
1016 if (p
< pmax
) *p
++ = *bg
;
1024 pmax
= p
+ (sizeof (bg_buf
) - 1);
1026 /* Mark suggested allowing for extra spplication specific stuff following
1027 * the background color. That is what the check for the semi-colon is for.
1029 while ((*bg
!= 0) && (*bg
!= ';'))
1031 if (p
< pmax
) *p
++ = *bg
;
1036 if (!strcmp (fg_buf
, "default") || !strcmp(bg_buf
, "default"))
1038 *fgp
= *bgp
= fg
= bg
= "default";
1042 *fgp
= fg
= check_color_for_digit_form (fg_buf
);
1043 *bgp
= bg
= check_color_for_digit_form (bg_buf
);
1049 static unsigned char FgBg_Stats
[JMAX_COLORS
];
1051 static int Color_0_Modified
= 0;
1053 void SLtt_set_color_object (int obj
, SLtt_Char_Type attr
)
1057 if ((obj
< 0) || (obj
>= JMAX_COLORS
)) return;
1059 cust_esc
= Ansi_Color_Map
[obj
].custom_esc
;
1060 if (cust_esc
!= NULL
)
1063 FgBg_Stats
[(Ansi_Color_Map
[obj
].fgbg
>> 8) & 0x7F] -= 1;
1064 Ansi_Color_Map
[obj
].custom_esc
= NULL
;
1067 Ansi_Color_Map
[obj
].fgbg
= attr
;
1068 if (obj
== 0) Color_0_Modified
= 1;
1070 if (_SLtt_color_changed_hook
!= NULL
)
1071 (*_SLtt_color_changed_hook
)();
1074 SLtt_Char_Type
SLtt_get_color_object (int obj
)
1076 if ((obj
< 0) || (obj
>= JMAX_COLORS
)) return 0;
1077 return Ansi_Color_Map
[obj
].fgbg
;
1080 void SLtt_add_color_attribute (int obj
, SLtt_Char_Type attr
)
1082 if ((obj
< 0) || (obj
>= JMAX_COLORS
)) return;
1084 Ansi_Color_Map
[obj
].fgbg
|= (attr
& ATTR_MASK
);
1085 if (obj
== 0) Color_0_Modified
= 1;
1086 if (_SLtt_color_changed_hook
!= NULL
)
1087 (*_SLtt_color_changed_hook
)();
1090 static SLtt_Char_Type
fb_to_fgbg (SLtt_Char_Type f
, SLtt_Char_Type b
)
1092 SLtt_Char_Type attr
;
1094 if (Max_Terminfo_Colors
!= 8)
1096 if (f
!= SLSMG_COLOR_DEFAULT
) f
%= Max_Terminfo_Colors
;
1097 if (b
!= SLSMG_COLOR_DEFAULT
) b
%= Max_Terminfo_Colors
;
1098 return ((f
<< 8) | (b
<< 16));
1101 /* Otherwise we have 8 ansi colors. Try to get bright versions
1102 * by using the BOLD and BLINK attributes.
1107 /* Note: If f represents default, it will have the value 0xFF */
1108 if (f
!= SLSMG_COLOR_DEFAULT
)
1110 if (f
& 0x8) attr
= SLTT_BOLD_MASK
;
1114 if (b
!= SLSMG_COLOR_DEFAULT
)
1116 if (b
& 0x8) attr
|= SLTT_BLINK_MASK
;
1120 return ((f
<< 8) | (b
<< 16) | attr
);
1123 /* This looks for colors with name form 'colorN'. If color is of this
1124 * form, N is passed back via paramter list.
1126 static int parse_color_digit_name (char *color
, SLtt_Char_Type
*f
)
1131 if (strncmp (color
, "color", 5))
1141 ch
= (unsigned char) *color
++;
1144 if ((ch
> '9') || (ch
< '0'))
1146 i
= 10 * i
+ (ch
- '0');
1149 *f
= (SLtt_Char_Type
) i
;
1153 static int make_color_fgbg (char *fg
, char *bg
, SLtt_Char_Type
*fgbg
)
1155 SLtt_Char_Type f
= 0xFFFFFFFFU
, b
= 0xFFFFFFFFU
;
1159 if ((fg
!= NULL
) && (*fg
== 0)) fg
= NULL
;
1160 if ((bg
!= NULL
) && (*bg
== 0)) bg
= NULL
;
1162 if ((fg
== NULL
) || (bg
== NULL
))
1164 if (-1 == get_default_colors (&dfg
, &dbg
))
1167 if (fg
== NULL
) fg
= dfg
;
1168 if (bg
== NULL
) bg
= dbg
;
1171 if (-1 == parse_color_digit_name (fg
, &f
))
1173 for (i
= 0; i
< MAX_COLOR_NAMES
; i
++)
1175 if (strcmp(fg
, Color_Defs
[i
].name
)) continue;
1176 f
= Color_Defs
[i
].color
;
1181 if (-1 == parse_color_digit_name (bg
, &b
))
1183 for (i
= 0; i
< MAX_COLOR_NAMES
; i
++)
1185 if (strcmp(bg
, Color_Defs
[i
].name
)) continue;
1186 b
= Color_Defs
[i
].color
;
1191 if ((f
== 0xFFFFFFFFU
) || (b
== 0xFFFFFFFFU
))
1194 *fgbg
= fb_to_fgbg (f
, b
);
1198 void SLtt_set_color (int obj
, char *what
, char *fg
, char *bg
)
1200 SLtt_Char_Type fgbg
;
1203 if ((obj
< 0) || (obj
>= JMAX_COLORS
))
1206 if (-1 != make_color_fgbg (fg
, bg
, &fgbg
))
1207 SLtt_set_color_object (obj
, fgbg
);
1210 void SLtt_set_color_fgbg (int obj
, SLtt_Char_Type f
, SLtt_Char_Type b
)
1212 SLtt_set_color_object (obj
, fb_to_fgbg (f
, b
));
1215 void SLtt_set_color_esc (int obj
, char *esc
)
1218 SLtt_Char_Type fgbg
= 0;
1221 if ((obj
< 0) || (obj
>= JMAX_COLORS
))
1226 cust_esc
= Ansi_Color_Map
[obj
].custom_esc
;
1227 if (cust_esc
!= NULL
)
1230 FgBg_Stats
[(Ansi_Color_Map
[obj
].fgbg
>> 8) & 0x7F] -= 1;
1233 cust_esc
= (char *) SLmalloc (strlen(esc
) + 1);
1234 if (cust_esc
!= NULL
) strcpy (cust_esc
, esc
);
1236 Ansi_Color_Map
[obj
].custom_esc
= cust_esc
;
1237 if (cust_esc
== NULL
) fgbg
= 0;
1240 /* The whole point of this is to generate a unique fgbg */
1241 for (i
= 0; i
< JMAX_COLORS
; i
++)
1243 if (FgBg_Stats
[i
] == 0) fgbg
= i
;
1245 if (obj
== i
) continue;
1246 if ((Ansi_Color_Map
[i
].custom_esc
) == NULL
) continue;
1247 if (!strcmp (Ansi_Color_Map
[i
].custom_esc
, cust_esc
))
1249 fgbg
= (Ansi_Color_Map
[i
].fgbg
>> 8) & 0x7F;
1253 FgBg_Stats
[fgbg
] += 1;
1257 Ansi_Color_Map
[obj
].fgbg
= (fgbg
| (fgbg
<< 8)) << 8;
1258 if (obj
== 0) Color_0_Modified
= 1;
1259 if (_SLtt_color_changed_hook
!= NULL
)
1260 (*_SLtt_color_changed_hook
)();
1263 void SLtt_set_alt_char_set (int i
)
1266 if (SLtt_Has_Alt_Charset
== 0) return;
1270 if (i
== last_i
) return;
1271 tt_write_string (i
? Start_Alt_Chars_Str
: End_Alt_Chars_Str
);
1275 static void write_attributes (SLtt_Char_Type fgbg
)
1278 int unknown_attributes
;
1280 if (Worthless_Highlight
) return;
1281 if (fgbg
== Current_Fgbg
) return;
1283 unknown_attributes
= 0;
1285 /* Before spitting out colors, fix attributes */
1286 if ((fgbg
& ATTR_MASK
) != (Current_Fgbg
& ATTR_MASK
))
1288 if (Current_Fgbg
& ATTR_MASK
)
1290 tt_write_string(Norm_Vid_Str
);
1291 /* In case normal video turns off ALL attributes: */
1292 if (fgbg
& SLTT_ALTC_MASK
)
1293 Current_Fgbg
&= ~SLTT_ALTC_MASK
;
1294 SLtt_set_alt_char_set (0);
1297 if ((fgbg
& SLTT_ALTC_MASK
)
1298 != (Current_Fgbg
& SLTT_ALTC_MASK
))
1300 SLtt_set_alt_char_set ((int) (fgbg
& SLTT_ALTC_MASK
));
1303 if (fgbg
& SLTT_ULINE_MASK
) tt_write_string (UnderLine_Vid_Str
);
1304 if (fgbg
& SLTT_BOLD_MASK
) SLtt_bold_video ();
1305 if (fgbg
& SLTT_REV_MASK
) tt_write_string (Rev_Vid_Str
);
1306 if (fgbg
& SLTT_BLINK_MASK
)
1308 /* Someday Linux will have a blink mode that set high intensity
1309 * background. Lets be prepared.
1311 if (SLtt_Blink_Mode
) tt_write_string (Blink_Vid_Str
);
1313 unknown_attributes
= 1;
1316 if (SLtt_Use_Ansi_Colors
)
1318 fg0
= (int) GET_FG(fgbg
);
1319 bg0
= (int) GET_BG(fgbg
);
1321 if (unknown_attributes
1322 || (fg0
!= (int)GET_FG(Current_Fgbg
)))
1324 if (fg0
== SLSMG_COLOR_DEFAULT
)
1325 tt_write_string (Default_Color_Fg_Str
);
1327 tt_printf (Color_Fg_Str
, COLOR_ARG(fg0
, Is_Fg_BGR
), 0);
1330 if (unknown_attributes
1331 || (bg0
!= (int)GET_BG(Current_Fgbg
)))
1333 if (bg0
== SLSMG_COLOR_DEFAULT
)
1334 tt_write_string (Default_Color_Bg_Str
);
1336 tt_printf (Color_Bg_Str
, COLOR_ARG(bg0
, Is_Bg_BGR
), 0);
1340 Current_Fgbg
= fgbg
;
1343 static int Video_Initialized
;
1345 void SLtt_reverse_video (int color
)
1347 SLtt_Char_Type fgbg
;
1350 if (Worthless_Highlight
) return;
1351 if ((color
< 0) || (color
>= JMAX_COLORS
)) return;
1353 if (Video_Initialized
== 0)
1355 if (color
== JNORMAL_COLOR
)
1357 tt_write_string (Norm_Vid_Str
);
1359 else tt_write_string (Rev_Vid_Str
);
1360 Current_Fgbg
= 0xFFFFFFFFU
;
1364 if (SLtt_Use_Ansi_Colors
)
1366 fgbg
= Ansi_Color_Map
[color
].fgbg
;
1367 if ((esc
= Ansi_Color_Map
[color
].custom_esc
) != NULL
)
1369 if (fgbg
!= Current_Fgbg
)
1371 Current_Fgbg
= fgbg
;
1372 tt_write_string (esc
);
1377 else fgbg
= Ansi_Color_Map
[color
].mono
;
1379 if (fgbg
== Current_Fgbg
) return;
1380 write_attributes (fgbg
);
1383 void SLtt_normal_video (void)
1385 SLtt_reverse_video(JNORMAL_COLOR
);
1388 void SLtt_narrow_width (void)
1390 tt_write_string("\033[?3l");
1393 void SLtt_wide_width (void)
1395 tt_write_string("\033[?3h");
1398 /* Highest bit represents the character set. */
1399 #define COLOR_MASK 0x7F00
1401 #if SLTT_HAS_NON_BCE_SUPPORT
1402 static int bce_color_eqs (unsigned int a
, unsigned int b
)
1404 a
= (a
& COLOR_MASK
) >> 8;
1405 b
= (b
& COLOR_MASK
) >> 8;
1410 if (SLtt_Use_Ansi_Colors
== 0)
1411 return Ansi_Color_Map
[a
].mono
== Ansi_Color_Map
[b
].mono
;
1413 if (Bce_Color_Offset
== 0)
1414 return Ansi_Color_Map
[a
].fgbg
== Ansi_Color_Map
[b
].fgbg
;
1416 /* If either are color 0, then we do not know what that means since the
1417 * terminal does not support BCE */
1418 if ((a
== 0) || (b
== 0))
1421 return Ansi_Color_Map
[a
-1].fgbg
== Ansi_Color_Map
[b
-1].fgbg
;
1423 #define COLOR_EQS(a,b) bce_color_eqs (a,b)
1425 # define COLOR_OF(x) (((unsigned int)(x) & COLOR_MASK) >> 8)
1426 # define COLOR_EQS(a, b) \
1427 (SLtt_Use_Ansi_Colors \
1428 ? (Ansi_Color_Map[COLOR_OF(a)].fgbg == Ansi_Color_Map[COLOR_OF(b)].fgbg)\
1429 : (Ansi_Color_Map[COLOR_OF(a)].mono == Ansi_Color_Map[COLOR_OF(b)].mono))
1432 #define CHAR_EQS(a, b) (((a) == (b))\
1433 || ((((a) & ~COLOR_MASK) == ((b) & ~COLOR_MASK))\
1434 && COLOR_EQS((a), (b))))
1436 /* The whole point of this routine is to prevent writing to the last column
1437 * and last row on terminals with automatic margins.
1439 static void write_string_with_care (char *str
)
1443 if (str
== NULL
) return;
1446 if (Automatic_Margins
&& (Cursor_r
+ 1 == SLtt_Screen_Rows
))
1448 if (len
+ (unsigned int) Cursor_c
>= (unsigned int) SLtt_Screen_Cols
)
1450 /* For now, just do not write there. Later, something more
1451 * sophisticated will be implemented.
1453 if (SLtt_Screen_Cols
> Cursor_c
)
1454 len
= SLtt_Screen_Cols
- Cursor_c
- 1;
1459 tt_write (str
, len
);
1462 static void send_attr_str (SLsmg_Char_Type
*s
)
1464 unsigned char out
[256], ch
, *p
;
1465 register SLtt_Char_Type attr
;
1466 register SLsmg_Char_Type sh
;
1467 int color
, last_color
= -1;
1470 while (0 != (sh
= *s
++))
1473 color
= ((int) sh
& 0xFF00) >> 8;
1475 #if SLTT_HAS_NON_BCE_SUPPORT
1476 if (Bce_Color_Offset
1477 && (color
>= Bce_Color_Offset
))
1478 color
-= Bce_Color_Offset
;
1481 if (color
!= last_color
)
1483 if (SLtt_Use_Ansi_Colors
) attr
= Ansi_Color_Map
[color
& 0x7F].fgbg
;
1484 else attr
= Ansi_Color_Map
[color
& 0x7F].mono
;
1486 if (sh
& 0x8000) /* alternate char set */
1488 if (SLtt_Use_Blink_For_ACS
)
1490 if (SLtt_Blink_Mode
) attr
|= SLTT_BLINK_MASK
;
1492 else attr
|= SLTT_ALTC_MASK
;
1495 if (attr
!= Current_Fgbg
)
1498 /* it is a space so only consider it different if it
1499 * has different attributes.
1501 (attr
!= Current_Fgbg
))
1502 /* The previous line was: */
1503 /* (attr & BGALL_MASK) != (Current_Fgbg & BGALL_MASK)) */
1504 /* However, it does not account for ACS */
1509 write_string_with_care ((char *) out
);
1510 Cursor_c
+= (int) (p
- out
);
1514 if (SLtt_Use_Ansi_Colors
&& (NULL
!= Ansi_Color_Map
[color
& 0x7F].custom_esc
))
1516 tt_write_string (Ansi_Color_Map
[color
& 0x7F].custom_esc
);
1517 /* Just in case the custom escape sequence screwed up
1518 * the alt character set state...
1520 if ((attr
& SLTT_ALTC_MASK
) != (Current_Fgbg
& SLTT_ALTC_MASK
))
1521 SLtt_set_alt_char_set ((int) (attr
& SLTT_ALTC_MASK
));
1522 Current_Fgbg
= attr
;
1524 else write_attributes (attr
);
1533 if (p
!= out
) write_string_with_care ((char *) out
);
1534 Cursor_c
+= (int) (p
- out
);
1537 static void forward_cursor (unsigned int n
, int row
)
1543 SLtt_normal_video ();
1544 SLMEMSET (buf
, ' ', n
);
1546 write_string_with_care (buf
);
1549 else if (Curs_F_Str
!= NULL
)
1552 n
= tt_sprintf(buf
, Curs_F_Str
, (int) n
, 0);
1555 else SLtt_goto_rc (row
, (int) (Cursor_c
+ n
));
1559 void SLtt_smart_puts(SLsmg_Char_Type
*neww
, SLsmg_Char_Type
*oldd
, int len
, int row
)
1561 register SLsmg_Char_Type
*p
, *q
, *qmax
, *pmax
, *buf
;
1562 SLsmg_Char_Type buffer
[256];
1563 unsigned int n_spaces
;
1564 SLsmg_Char_Type
*space_match
, *last_buffered_match
;
1565 #ifdef HP_GLITCH_CODE
1566 int handle_hp_glitch
= 0;
1568 SLsmg_Char_Type space_char
;
1569 #define SLTT_USE_INSERT_HACK 1
1570 #if SLTT_USE_INSERT_HACK
1571 SLsmg_Char_Type insert_hack_prev
= 0;
1572 SLsmg_Char_Type insert_hack_char
= 0;
1574 if ((row
+ 1 == SLtt_Screen_Rows
)
1575 && (len
== SLtt_Screen_Cols
)
1577 && (SLtt_Term_Cannot_Insert
== 0)
1578 && Automatic_Margins
)
1580 insert_hack_char
= neww
[len
-1];
1581 if (oldd
[len
-1] == insert_hack_char
)
1582 insert_hack_char
= 0;
1584 insert_hack_prev
= neww
[len
-2];
1592 /* Find out where to begin --- while they match, we are ok */
1595 if (q
== qmax
) return;
1596 #if SLANG_HAS_KANJI_SUPPORT
1598 { /* new is kanji */
1599 if ((*q
& 0x80) && ((q
+ 1) < qmax
))
1600 { /* old is also kanji */
1601 if (((0xFF & *q
) != (0xFF & *p
))
1602 || ((0xFF & q
[1]) != (0xFF & p
[1])))
1603 break; /* both kanji, but not match */
1606 { /* kanji match ! */
1607 if (!COLOR_EQS(*q
, *p
)) break;
1609 if (!COLOR_EQS(*q
, *p
)) break;
1615 else break; /* old is not kanji */
1618 { /* new is not kanji */
1619 if (*q
& 0x80) break; /* old is kanji */
1622 if (!CHAR_EQS(*q
, *p
)) break;
1626 #ifdef HP_GLITCH_CODE
1629 SLsmg_Char_Type
*qq
= q
;
1631 SLtt_goto_rc (row
, (int) (p
- neww
));
1637 SLtt_normal_video ();
1640 handle_hp_glitch
= 1;
1647 /* Find where the last non-blank character on old/new screen is */
1650 if ((*(pmax
-1) & 0xFF) == ' ')
1652 /* If we get here, then we can erase to the end of the line to create
1653 * the final space. However, this will only work _if_ erasing will
1654 * get us the correct color. If the terminal supports BCE, then this
1655 * is easy. If it does not, then we can only perform this operation
1656 * if the color is known via something like COLORFGBG. For now,
1657 * I just will not perform the optimization for such terminals.
1659 if ((Can_Background_Color_Erase
)
1660 && SLtt_Use_Ansi_Colors
)
1661 space_char
= *(pmax
- 1);
1666 if (!CHAR_EQS(*pmax
, space_char
))
1677 if (!CHAR_EQS(*qmax
, space_char
))
1684 last_buffered_match
= buf
= buffer
; /* buffer is empty */
1686 #ifdef HP_GLITCH_CODE
1687 if (handle_hp_glitch
)
1696 #ifdef HP_GLITCH_CODE
1697 if (Has_HP_Glitch
== 0)
1700 /* Try use use erase to bol if possible */
1701 if ((Del_Bol_Str
!= NULL
) && ((*neww
& 0xFF) == 32))
1703 SLsmg_Char_Type
*p1
;
1704 SLsmg_Char_Type blank
;
1707 if ((Can_Background_Color_Erase
)
1708 && SLtt_Use_Ansi_Colors
)
1710 /* black+white attributes do not support bce */
1714 while ((p1
< pmax
) && (CHAR_EQS (*p1
, blank
)))
1717 /* Is this optimization worth it? Assume Del_Bol_Str is ESC [ 1 K
1718 * It costs 4 chars + the space needed to properly position the
1719 * cursor, e.g., ESC [ 10;10H. So, it costs at least 13 characters.
1721 if ((p1
> neww
+ 13)
1723 /* Avoid erasing from the end of the line */
1724 && ((p1
!= pmax
) || (pmax
< neww
+ len
)))
1726 int ofs
= (int) (p1
- neww
);
1729 SLtt_goto_rc (row
, ofs
- 1);
1730 SLtt_reverse_video (blank
>> 8);
1731 tt_write_string (Del_Bol_Str
);
1736 SLtt_goto_rc (row
, (int) (p
- neww
));
1739 SLtt_goto_rc (row
, (int) (p
- neww
));
1740 #ifdef HP_GLITCH_CODE
1745 /* loop using overwrite then skip algorithm until done */
1748 /* while they do not match and we do not hit a space, buffer them up */
1752 if (CHAR_EQS(*q
, 32) && CHAR_EQS(*p
, 32))
1754 /* If *q is not a space, we would have to overwrite it.
1755 * However, if *q is a space, then while *p is also one,
1756 * we only need to skip over the blank field.
1762 && CHAR_EQS(*p
, 32))
1767 n_spaces
= (unsigned int) (p
- space_match
);
1770 #if SLANG_HAS_KANJI_SUPPORT
1771 if ((*p
& 0x80) && ((p
+ 1) < pmax
))
1772 { /* new is kanji */
1774 { /* old is also kanji */
1775 if (((0xFF & *q
) != (0xFF & *p
))
1776 || ((0xFF & q
[1]) != (0xFF & p
[1])))
1778 /* both kanji, but not match */
1785 { /* kanji match ? */
1786 if (!COLOR_EQS(*q
, *p
) || !COLOR_EQS(*(q
+1), *(p
+1)))
1788 /* code is match, but color is diff */
1794 /* really match ! */
1799 { /* old is not kanji */
1807 { /* new is not kanji */
1809 { /* old is kanji */
1817 if (CHAR_EQS(*q
, *p
)) break;
1823 if (buf
!= buffer
) send_attr_str (buffer
);
1827 && ((p
< pmax
) /* erase to eol will achieve this effect*/
1828 || (space_char
!= 32)))/* unless space_char is not a simple space */
1830 forward_cursor (n_spaces
, row
);
1833 /* Now we overwrote what we could and cursor is placed at position
1834 * of a possible match of new and old. If this is the case, skip
1837 #if !SLANG_HAS_KANJI_SUPPORT
1838 while ((p
< pmax
) && CHAR_EQS(*p
, *q
))
1847 if ((*p
& 0x80) && ((p
+ 1) < pmax
))
1848 { /* new is kanji */
1850 { /* old is also kanji */
1851 if (((0xFF & *q
) == (0xFF & *p
))
1852 && ((0xFF & q
[1]) == (0xFF & p
[1])))
1855 if (!COLOR_EQS(*q
, *p
)
1856 || !COLOR_EQS(q
[1], p
[1]))
1874 else break; /* both kanji, but not match */
1876 else break; /* old is not kanji */
1879 { /* new is not kanji */
1880 if (*q
& 0x80) break; /* old is kanji */
1881 if (!CHAR_EQS(*q
, *p
)) break;
1887 last_buffered_match
= buf
;
1888 if (p
>= pmax
) break;
1890 /* jump to new position is it is greater than 5 otherwise
1891 * let it sit in the buffer and output it later.
1893 if ((int) (buf
- buffer
) >= 5)
1895 forward_cursor ((unsigned int) (buf
- buffer
), row
);
1896 last_buffered_match
= buf
= buffer
;
1904 if ((buf
== last_buffered_match
)
1905 && ((int) (buf
- buffer
) >= 5))
1907 forward_cursor ((unsigned int) (buf
- buffer
), row
);
1912 send_attr_str (buffer
);
1919 SLtt_reverse_video (space_char
>> 8);
1923 #if SLTT_USE_INSERT_HACK
1924 else if (insert_hack_char
)
1926 SLtt_goto_rc (SLtt_Screen_Rows
-1, SLtt_Screen_Cols
-2);
1927 buffer
[0] = insert_hack_char
;
1929 send_attr_str (buffer
);
1930 SLtt_goto_rc (SLtt_Screen_Rows
-1, SLtt_Screen_Cols
-2);
1931 buffer
[0] = insert_hack_prev
;
1932 SLtt_begin_insert ();
1933 send_attr_str (buffer
);
1938 if (Automatic_Margins
&& (Cursor_c
+ 1 >= SLtt_Screen_Cols
)) Cursor_Set
= 0;
1941 static void get_color_info (void)
1945 /* Allow easy mechanism to override inadequate termcap/terminfo files. */
1946 if (SLtt_Use_Ansi_Colors
== 0)
1947 SLtt_Use_Ansi_Colors
= (NULL
!= getenv ("COLORTERM"));
1949 if (SLtt_Use_Ansi_Colors
)
1950 Is_Color_Terminal
= 1;
1952 #if SLTT_HAS_NON_BCE_SUPPORT
1953 if (Can_Background_Color_Erase
== 0)
1954 Can_Background_Color_Erase
= (NULL
!= getenv ("COLORTERM_BCE"));
1957 if (-1 == get_default_colors (&fg
, &bg
))
1960 /* Check to see if application has already set them. */
1961 if (Color_0_Modified
)
1964 SLtt_set_color (0, NULL
, fg
, bg
);
1965 SLtt_set_color (1, NULL
, bg
, fg
);
1972 static int Termcap_Initalized
= 0;
1975 /* Termcap based system */
1976 static char Termcap_Buf
[4096];
1977 static char Termcap_String_Buf
[4096];
1978 static char *Termcap_String_Ptr
;
1979 extern char *tgetstr(char *, char **);
1980 extern int tgetent(char *, char *);
1981 extern int tgetnum(char *);
1982 extern int tgetflag(char *);
1985 static SLterminfo_Type
*Terminfo
;
1988 #define TGETFLAG(x) (SLtt_tgetflag(x) > 0)
1990 static char *fixup_tgetstr (char *what
)
1992 register char *w
, *w1
;
1998 /* Check for AIX brain-damage */
2002 /* lose pad info --- with today's technology, term is a loser if
2003 it is really needed */
2004 while ((*what
== '.') ||
2005 ((*what
>= '0') && (*what
<= '9'))) what
++;
2006 if (*what
== '*') what
++;
2008 /* lose terminfo padding--- looks like $<...> */
2010 while (*w
) if ((*w
++ == '$') && (*w
== '<'))
2013 while (*w
&& (*w
!= '>')) w
++;
2017 while ((*w1
++ = *w
++) != 0);
2021 if (*what
== 0) what
= NULL
;
2025 char *SLtt_tgetstr (char *cap
)
2029 if (Termcap_Initalized
== 0)
2033 s
= tgetstr (cap
, &Termcap_String_Ptr
);
2035 s
= _SLtt_tigetstr (Terminfo
, cap
);
2038 /* Do not strip pad info for alternate character set. I need to make
2039 * this more general.
2041 /* FIXME: Priority=low; */
2042 if (0 == strcmp (cap
, "ac"))
2045 return fixup_tgetstr (s
);
2048 int SLtt_tgetnum (char *s
)
2050 if (Termcap_Initalized
== 0)
2055 return _SLtt_tigetnum (Terminfo
, s
);
2059 int SLtt_tgetflag (char *s
)
2061 if (Termcap_Initalized
== 0)
2064 return tgetflag (s
);
2066 return _SLtt_tigetflag (Terminfo
, s
);
2070 static int Vt100_Like
= 0;
2072 void SLtt_get_terminfo (void)
2077 term
= getenv ("TERM");
2079 SLang_exit_error("TERM environment variable needs set.");
2081 if (0 == (status
= SLtt_initialize (term
)))
2086 SLang_exit_error ("Unknown terminal: %s\n\
2087 Check the TERM environment variable.\n\
2088 Also make sure that the terminal is defined in the terminfo database.\n\
2089 Alternatively, set the TERMCAP environment variable to the desired\n\
2096 SLang_exit_error ("\
2097 Your terminal lacks the ability to clear the screen or position the cursor.\n");
2101 /* Returns 0 if all goes well, -1 if terminal capabilities cannot be deduced,
2102 * or -2 if terminal cannot position the cursor.
2104 int SLtt_initialize (char *term
)
2110 if (SLang_TT_Write_FD
== -1)
2112 /* Apparantly, this cannot fail according to the man pages. */
2113 SLang_TT_Write_FD
= fileno (stdout
);
2118 term
= getenv ("TERM");
2123 Linux_Console
= (!strncmp (term
, "linux", 5)
2125 || !strncmp(term
, "con", 3)
2131 if (strcmp(t
, "vt52") && (*t
++ == 'v') && (*t
++ == 't')
2132 && (ch
= *t
, (ch
>= '1') && (ch
<= '9'))) Vt100_Like
= 1;
2134 is_xterm
= ((0 == strncmp (term
, "xterm", 5))
2135 || (0 == strncmp (term
, "rxvt", 4))
2136 || (0 == strncmp (term
, "Eterm", 5)));
2138 almost_vtxxx
= (Vt100_Like
2141 || !strcmp (term
, "screen"));
2143 # ifndef USE_TERMCAP
2144 if (NULL
== (Terminfo
= _SLtt_tigetent (term
)))
2146 if (almost_vtxxx
) /* Special cases. */
2149 if (!strcmp (term
, "vt100")) vt102
= 0;
2151 SLtt_set_term_vtxxx (&vt102
);
2152 (void) SLtt_get_screen_size ();
2157 # else /* USE_TERMCAP */
2158 if (1 != tgetent(Termcap_Buf
, term
))
2160 Termcap_String_Ptr
= Termcap_String_Buf
;
2161 # endif /* NOT USE_TERMCAP */
2163 Termcap_Initalized
= 1;
2165 Cls_Str
= SLtt_tgetstr ("cl");
2166 Curs_Pos_Str
= SLtt_tgetstr ("cm");
2168 if ((NULL
== (Ins_Mode_Str
= SLtt_tgetstr("im")))
2169 || ( NULL
== (Eins_Mode_Str
= SLtt_tgetstr("ei")))
2170 || ( NULL
== (Del_Char_Str
= SLtt_tgetstr("dc"))))
2171 SLtt_Term_Cannot_Insert
= 1;
2173 Visible_Bell_Str
= SLtt_tgetstr ("vb");
2174 Curs_Up_Str
= SLtt_tgetstr ("up");
2175 Rev_Scroll_Str
= SLtt_tgetstr("sr");
2176 Del_N_Lines_Str
= SLtt_tgetstr("DL");
2177 Add_N_Lines_Str
= SLtt_tgetstr("AL");
2179 /* Actually these are used to initialize terminals that use cursor
2180 * addressing. Hard to believe.
2182 Term_Init_Str
= SLtt_tgetstr ("ti");
2183 Term_Reset_Str
= SLtt_tgetstr ("te");
2185 /* If I do this for vtxxx terminals, arrow keys start sending ESC O A,
2186 * which I do not want. This is mainly for HP terminals.
2188 if ((almost_vtxxx
== 0) || SLtt_Force_Keypad_Init
)
2190 Keypad_Init_Str
= SLtt_tgetstr ("ks");
2191 Keypad_Reset_Str
= SLtt_tgetstr ("ke");
2194 /* Make up for defective termcap/terminfo databases */
2195 if ((Vt100_Like
&& (term
[2] != '1'))
2200 if (Del_N_Lines_Str
== NULL
) Del_N_Lines_Str
= "\033[%dM";
2201 if (Add_N_Lines_Str
== NULL
) Add_N_Lines_Str
= "\033[%dL";
2204 Scroll_R_Str
= SLtt_tgetstr("cs");
2206 SLtt_get_screen_size ();
2208 if ((Scroll_R_Str
== NULL
)
2209 || (((NULL
== Del_N_Lines_Str
) || (NULL
== Add_N_Lines_Str
))
2210 && (NULL
== Rev_Scroll_Str
)))
2216 /* Defective termcap mode!!!! */
2217 SLtt_set_term_vtxxx (NULL
);
2219 else SLtt_Term_Cannot_Scroll
= 1;
2222 Del_Eol_Str
= SLtt_tgetstr("ce");
2223 Del_Bol_Str
= SLtt_tgetstr("cb");
2224 if (is_xterm
&& (Del_Bol_Str
== NULL
))
2225 Del_Bol_Str
= "\033[1K";
2226 if (is_xterm
&& (Del_Eol_Str
== NULL
))
2227 Del_Bol_Str
= "\033[K";
2229 Rev_Vid_Str
= SLtt_tgetstr("mr");
2230 if (Rev_Vid_Str
== NULL
) Rev_Vid_Str
= SLtt_tgetstr("so");
2232 Bold_Vid_Str
= SLtt_tgetstr("md");
2234 /* Although xterm cannot blink, it does display the blinking characters
2235 * as bold ones. Some Rxvt will display the background as high intensity.
2237 if ((NULL
== (Blink_Vid_Str
= SLtt_tgetstr("mb")))
2239 Blink_Vid_Str
= "\033[5m";
2241 UnderLine_Vid_Str
= SLtt_tgetstr("us");
2243 Start_Alt_Chars_Str
= SLtt_tgetstr ("as"); /* smacs */
2244 End_Alt_Chars_Str
= SLtt_tgetstr ("ae"); /* rmacs */
2245 Enable_Alt_Char_Set
= SLtt_tgetstr ("eA"); /* enacs */
2246 SLtt_Graphics_Char_Pairs
= SLtt_tgetstr ("ac");
2248 if (NULL
== SLtt_Graphics_Char_Pairs
)
2250 /* make up for defective termcap/terminfo */
2253 Start_Alt_Chars_Str
= "\016";
2254 End_Alt_Chars_Str
= "\017";
2255 Enable_Alt_Char_Set
= "\033)0";
2259 /* aixterm added by willi */
2260 if (is_xterm
|| !strncmp (term
, "aixterm", 7))
2262 Start_Alt_Chars_Str
= "\016";
2263 End_Alt_Chars_Str
= "\017";
2264 Enable_Alt_Char_Set
= "\033(B\033)0";
2267 if ((SLtt_Graphics_Char_Pairs
== NULL
) &&
2268 ((Start_Alt_Chars_Str
== NULL
) || (End_Alt_Chars_Str
== NULL
)))
2270 SLtt_Has_Alt_Charset
= 0;
2271 Enable_Alt_Char_Set
= NULL
;
2273 else SLtt_Has_Alt_Charset
= 1;
2276 Enable_Alt_Char_Set
= Start_Alt_Chars_Str
= End_Alt_Chars_Str
= NULL
;
2279 /* status line capabilities */
2280 if ((SLtt_Has_Status_Line
== -1)
2281 && (0 != (SLtt_Has_Status_Line
= TGETFLAG ("hs"))))
2283 Disable_Status_line_Str
= SLtt_tgetstr ("ds");
2284 Return_From_Status_Line_Str
= SLtt_tgetstr ("fs");
2285 Goto_Status_Line_Str
= SLtt_tgetstr ("ts");
2286 /* Status_Line_Esc_Ok = TGETFLAG("es"); */
2287 Num_Status_Line_Columns
= SLtt_tgetnum ("ws");
2288 if (Num_Status_Line_Columns
< 0) Num_Status_Line_Columns
= 0;
2291 if (NULL
== (Norm_Vid_Str
= SLtt_tgetstr("me")))
2293 Norm_Vid_Str
= SLtt_tgetstr("se");
2296 Cursor_Invisible_Str
= SLtt_tgetstr("vi");
2297 Cursor_Visible_Str
= SLtt_tgetstr("ve");
2299 Curs_F_Str
= SLtt_tgetstr("RI");
2302 if (NULL
!= Curs_F_Str
)
2304 Len_Curs_F_Str
= strlen(Curs_F_Str
);
2306 else Len_Curs_F_Str
= strlen(Curs_Pos_Str
);
2309 Automatic_Margins
= TGETFLAG ("am");
2310 /* No_Move_In_Standout = !TGETFLAG ("ms"); */
2311 # ifdef HP_GLITCH_CODE
2312 Has_HP_Glitch
= TGETFLAG ("xs");
2314 Worthless_Highlight
= TGETFLAG ("xs");
2317 if (Worthless_Highlight
== 0)
2318 { /* Magic cookie glitch */
2319 Worthless_Highlight
= (SLtt_tgetnum ("sg") > 0);
2322 if (Worthless_Highlight
)
2323 SLtt_Has_Alt_Charset
= 0;
2325 Reset_Color_String
= SLtt_tgetstr ("op");
2326 Color_Fg_Str
= SLtt_tgetstr ("AF"); /* ANSI setaf */
2327 if (Color_Fg_Str
== NULL
)
2329 Color_Fg_Str
= SLtt_tgetstr ("Sf"); /* setf */
2330 Is_Fg_BGR
= (Color_Fg_Str
!= NULL
);
2332 Color_Bg_Str
= SLtt_tgetstr ("AB"); /* ANSI setab */
2333 if (Color_Bg_Str
== NULL
)
2335 Color_Bg_Str
= SLtt_tgetstr ("Sb"); /* setb */
2336 Is_Bg_BGR
= (Color_Bg_Str
!= NULL
);
2339 if ((Max_Terminfo_Colors
= SLtt_tgetnum ("Co")) < 0)
2340 Max_Terminfo_Colors
= 8;
2342 if ((Color_Bg_Str
!= NULL
) && (Color_Fg_Str
!= NULL
))
2343 SLtt_Use_Ansi_Colors
= 1;
2347 Color_Fg_Str
= "%?%p1%{7}%>%t\033[1;3%p1%{8}%m%dm%e\033[3%p1%dm%;";
2348 Color_Bg_Str
= "%?%p1%{7}%>%t\033[5;4%p1%{8}%m%dm%e\033[4%p1%dm%;";
2349 Max_Terminfo_Colors
= 16;
2351 Color_Fg_Str
= "\033[3%dm";
2352 Color_Bg_Str
= "\033[4%dm";
2353 Max_Terminfo_Colors
= 8;
2357 #if SLTT_HAS_NON_BCE_SUPPORT
2358 Can_Background_Color_Erase
= TGETFLAG ("ut"); /* bce */
2359 /* Modern xterms have the BCE capability as well as the linux console */
2360 if (Can_Background_Color_Erase
== 0)
2362 Can_Background_Color_Erase
= (Linux_Console
2363 # if SLTT_XTERM_ALWAYS_BCE
2372 if ((Cls_Str
== NULL
)
2373 || (Curs_Pos_Str
== NULL
))
2382 /* specific to vtxxx only */
2383 void SLtt_enable_cursor_keys (void)
2388 tt_write_string("\033=\033[?1l");
2392 int SLtt_initialize (char *term
)
2394 SLtt_get_terminfo ();
2398 void SLtt_get_terminfo ()
2402 Color_Fg_Str
= "\033[3%dm";
2403 Color_Bg_Str
= "\033[4%dm";
2404 Max_Terminfo_Colors
= 8;
2408 SLtt_set_term_vtxxx(&zero
);
2409 Start_Alt_Chars_Str
= "\016";
2410 End_Alt_Chars_Str
= "\017";
2411 SLtt_Has_Alt_Charset
= 1;
2412 SLtt_Graphics_Char_Pairs
= "aaffgghhjjkkllmmnnooqqssttuuvvwwxx";
2413 Enable_Alt_Char_Set
= "\033(B\033)0";
2414 SLtt_get_screen_size ();
2418 /* This sets term for vt102 terminals it parameter vt100 is 0. If vt100
2419 * is non-zero, set terminal appropriate for a only vt100
2420 * (no add line capability). */
2422 void SLtt_set_term_vtxxx(int *vt100
)
2424 Norm_Vid_Str
= "\033[m";
2426 Scroll_R_Str
= "\033[%i%d;%dr";
2427 Cls_Str
= "\033[2J\033[H";
2428 Rev_Vid_Str
= "\033[7m";
2429 Bold_Vid_Str
= "\033[1m";
2430 Blink_Vid_Str
= "\033[5m";
2431 UnderLine_Vid_Str
= "\033[4m";
2432 Del_Eol_Str
= "\033[K";
2433 Del_Bol_Str
= "\033[1K";
2434 Rev_Scroll_Str
= "\033M";
2435 Curs_F_Str
= "\033[%dC";
2436 /* Len_Curs_F_Str = 5; */
2437 Curs_Pos_Str
= "\033[%i%d;%dH";
2438 if ((vt100
== NULL
) || (*vt100
== 0))
2440 Ins_Mode_Str
= "\033[4h";
2441 Eins_Mode_Str
= "\033[4l";
2442 Del_Char_Str
= "\033[P";
2443 Del_N_Lines_Str
= "\033[%dM";
2444 Add_N_Lines_Str
= "\033[%dL";
2445 SLtt_Term_Cannot_Insert
= 0;
2449 Del_N_Lines_Str
= NULL
;
2450 Add_N_Lines_Str
= NULL
;
2451 SLtt_Term_Cannot_Insert
= 1;
2453 SLtt_Term_Cannot_Scroll
= 0;
2454 /* No_Move_In_Standout = 0; */
2457 int SLtt_init_video (void)
2459 /* send_string_to_term("\033[?6h"); */
2460 /* relative origin mode */
2461 tt_write_string (Term_Init_Str
);
2462 tt_write_string (Keypad_Init_Str
);
2463 SLtt_reset_scroll_region();
2465 tt_write_string (Enable_Alt_Char_Set
);
2466 Video_Initialized
= 1;
2470 int SLtt_reset_video (void)
2472 SLtt_goto_rc (SLtt_Screen_Rows
- 1, 0);
2474 SLtt_normal_video (); /* MSKermit requires this */
2475 tt_write_string(Norm_Vid_Str
);
2477 Current_Fgbg
= 0xFFFFFFFFU
;
2478 SLtt_set_alt_char_set (0);
2479 if (SLtt_Use_Ansi_Colors
)
2481 if (Reset_Color_String
== NULL
)
2483 SLtt_Char_Type attr
;
2484 if (-1 != make_color_fgbg (NULL
, NULL
, &attr
))
2485 write_attributes (attr
);
2486 else tt_write_string ("\033[0m\033[m");
2488 else tt_write_string (Reset_Color_String
);
2489 Current_Fgbg
= 0xFFFFFFFFU
;
2492 tt_write_string (Keypad_Reset_Str
);
2493 tt_write_string (Term_Reset_Str
);
2494 SLtt_flush_output ();
2495 Video_Initialized
= 0;
2499 void SLtt_bold_video (void)
2501 tt_write_string (Bold_Vid_Str
);
2504 int SLtt_set_mouse_mode (int mode
, int force
)
2510 if (NULL
== (term
= (char *) getenv("TERM"))) return -1;
2511 if (strncmp ("xterm", term
, 5))
2516 tt_write_string ("\033[?9h");
2518 tt_write_string ("\033[?9l");
2523 void SLtt_disable_status_line (void)
2525 if (SLtt_Has_Status_Line
> 0)
2527 tt_write_string (Disable_Status_line_Str
);
2528 SLtt_flush_output ();
2532 int SLtt_write_to_status_line (char *s
, int col
)
2534 if ((SLtt_Has_Status_Line
<= 0)
2535 || (Goto_Status_Line_Str
== NULL
)
2536 || (Return_From_Status_Line_Str
== NULL
))
2539 tt_printf (Goto_Status_Line_Str
, col
, 0);
2540 tt_write_string (s
);
2541 tt_write_string (Return_From_Status_Line_Str
);
2545 void SLtt_get_screen_size (void)
2549 unsigned short chan
;
2550 $
DESCRIPTOR(dev_dsc
, "SYS$INPUT:");
2555 struct winsize wind_struct
;
2559 if ((ioctl(1,TIOCGWINSZ
,&wind_struct
) == 0)
2560 || (ioctl(0, TIOCGWINSZ
, &wind_struct
) == 0)
2561 || (ioctl(2, TIOCGWINSZ
, &wind_struct
) == 0))
2563 c
= (int) wind_struct
.ws_col
;
2564 r
= (int) wind_struct
.ws_row
;
2568 while (errno
== EINTR
);
2573 status
= sys$
assign(&dev_dsc
,&chan
,0,0,0);
2576 code
= DVI$_DEVBUFSIZ
;
2577 status
= lib$
getdvi(&code
, &chan
,0, &c
, 0,0);
2580 code
= DVI$_TT_PAGE
;
2581 status
= lib$
getdvi(&code
, &chan
,0, &r
, 0,0);
2590 char *s
= getenv ("LINES");
2591 if (s
!= NULL
) r
= atoi (s
);
2596 char *s
= getenv ("COLUMNS");
2597 if (s
!= NULL
) c
= atoi (s
);
2603 if ((r
<= 0) || (r
> 200)) r
= 24;
2604 if ((c
<= 0) || (c
> 250)) c
= 80;
2606 SLtt_Screen_Rows
= r
;
2607 SLtt_Screen_Cols
= c
;
2610 #if SLTT_HAS_NON_BCE_SUPPORT
2611 int _SLtt_get_bce_color_offset (void)
2613 if ((SLtt_Use_Ansi_Colors
== 0)
2614 || Can_Background_Color_Erase
2615 || SLtt_Use_Blink_For_ACS
) /* in this case, we cannot lose a color */
2616 Bce_Color_Offset
= 0;
2619 if (GET_BG(Ansi_Color_Map
[0].fgbg
) == SLSMG_COLOR_DEFAULT
)
2620 Bce_Color_Offset
= 0;
2622 Bce_Color_Offset
= 1;
2625 return Bce_Color_Offset
;