2 Copyright (C) 2004, 2005, 2006 John E. Davis
4 This file is part of the S-Lang Library.
6 The S-Lang Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
11 The S-Lang Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this library; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
27 #if !defined(VMS) || (__VMS_VER >= 70000000)
28 # include <sys/time.h>
30 # include <sys/select.h>
32 # include <sys/types.h>
36 /* Prototype for select */
37 # include <net/socket.h>
49 # include <lib$routines.h>
53 # include <sys/ioctl.h>
58 # include <sys/termio.h>
59 # include <sys/stream.h>
60 # include <sys/ptem.h>
64 #if defined (_AIX) && !defined (FD_SET)
65 # include <sys/select.h> /* for FD_ISSET, FD_SET, FD_ZERO */
70 #if defined(__DECC) && defined(VMS)
71 /* These get prototypes for write an sleep */
79 /* Colors: These definitions are used for the display. However, the
80 * application only uses object handles which get mapped to this
81 * internal representation. The mapping is performed by the Color_Map
84 #define CHAR_MASK 0x000000FF
85 #define FG_MASK 0x0000FF00
86 #define BG_MASK 0x00FF0000
87 #define ATTR_MASK 0x1F000000
88 #define BGALL_MASK 0x0FFF0000
90 /* The 0x10000000 bit represents the alternate character set. BGALL_MASK does
91 * not include this attribute.
94 #define GET_FG(fgbg) (((fgbg) & FG_MASK) >> 8)
95 #define GET_BG(fgbg) (((fgbg) & BG_MASK) >> 16)
96 #define MAKE_COLOR(fg, bg) (((fg) | ((bg) << 8)) << 8)
98 int SLtt_Screen_Cols
= 80;
99 int SLtt_Screen_Rows
= 24;
100 int SLtt_Term_Cannot_Insert
;
101 int SLtt_Term_Cannot_Scroll
;
102 int SLtt_Use_Ansi_Colors
;
103 int SLtt_Blink_Mode
= 0;
104 int SLtt_Use_Blink_For_ACS
= 0;
105 int SLtt_Newline_Ok
= 0;
106 int SLtt_Has_Alt_Charset
= 0;
107 int SLtt_Force_Keypad_Init
= 0;
109 /* static int UTF8_Mode = -1; */
111 void (*_pSLtt_color_changed_hook
)(void);
113 #if SLTT_HAS_NON_BCE_SUPPORT
114 static int Bce_Color_Offset
= 0;
116 static int Can_Background_Color_Erase
= 1;
118 /* -1 means unknown */
119 int SLtt_Has_Status_Line
= -1; /* hs */
120 int SLang_TT_Write_FD
= -1;
122 static int Automatic_Margins
;
123 /* static int No_Move_In_Standout; */
124 static int Worthless_Highlight
;
125 #define HP_GLITCH_CODE
126 #ifdef HP_GLITCH_CODE
127 /* This glitch is exclusive to HP term. Basically it means that to clear
128 * attributes, one has to erase to the end of the line.
130 static int Has_HP_Glitch
;
133 static char *Reset_Color_String
;
134 static int Is_Color_Terminal
= 0;
136 static int Linux_Console
;
137 static int QANSI_Console
;
138 static int Mouse_Mode
= -1;
140 /* The following comment is nolonger valid, but is here in case there are
141 * some apps that use SLtt_Use_Blink_For_ACS and still need porting to v2.
143 * It is crucial that JMAX_COLORS must be less than 128 since the high bit
144 * is used to indicate a character from the ACS (alt char set). The exception
145 * to this rule is if SLtt_Use_Blink_For_ACS is true. This means that of
146 * the highbit is set, we interpret that as a blink character. This is
147 * exploited by DOSemu.
149 #define JMAX_COLORS 512
150 #define JNORMAL_COLOR 0
159 static Brush_Info_Type Brush_Table
[JMAX_COLORS
];
161 /* 0 if least significant bit is blue, not red */
162 /* static int Is_Fg_BGR = 0; */
163 static int Is_Bg_BGR
= 0;
164 #define COLOR_ARG(color, is_bgr) ((is_bgr) ? RGB_to_BGR[(color)&0x7] : (color))
165 static SLCONST
int RGB_to_BGR
[] =
167 0, 4, 2, 6, 1, 5, 3, 7
171 static char *Color_Fg_Str
= "\033[3%dm";
172 static char *Color_Bg_Str
= "\033[4%dm";
173 static char *Default_Color_Fg_Str
= "\033[39m";
174 static char *Default_Color_Bg_Str
= "\033[49m";
176 static int Max_Terminfo_Colors
= 8; /* termcap Co */
178 char *SLtt_Graphics_Char_Pairs
; /* ac termcap string -- def is vt100 */
180 /* 1 if terminal lacks the ability to go into insert mode or into delete
181 mode. Currently controlled by S-Lang but later perhaps termcap. */
183 static char *UnderLine_Vid_Str
;
184 static char *Blink_Vid_Str
;
185 static char *Bold_Vid_Str
;
186 static char *Ins_Mode_Str
; /* = "\033[4h"; */ /* ins mode (im) */
187 static char *Eins_Mode_Str
; /* = "\033[4l"; */ /* end ins mode (ei) */
188 static char *Scroll_R_Str
; /* = "\033[%d;%dr"; */ /* scroll region */
189 static char *Cls_Str
; /* = "\033[2J\033[H"; */ /* cl termcap STR for ansi terminals */
190 static char *Rev_Vid_Str
; /* = "\033[7m"; */ /* mr,so termcap string */
191 static char *Norm_Vid_Str
; /* = "\033[m"; */ /* me,se termcap string */
192 static char *Del_Eol_Str
; /* = "\033[K"; */ /* ce */
193 static char *Del_Bol_Str
; /* = "\033[1K"; */ /* cb */
194 static char *Del_Char_Str
; /* = "\033[P"; */ /* dc */
195 static char *Del_N_Lines_Str
; /* = "\033[%dM"; */ /* DL */
196 static char *Add_N_Lines_Str
; /* = "\033[%dL"; */ /* AL */
197 static char *Rev_Scroll_Str
;
198 static char *Curs_Up_Str
;
199 static char *Curs_F_Str
; /* RI termcap string */
200 static char *Cursor_Visible_Str
; /* ve termcap string */
201 static char *Cursor_Invisible_Str
; /* vi termcap string */
203 static char *Start_Mouse_Rpt_Str
; /* Start mouse reporting mode */
204 static char *End_Mouse_Rpt_Str
; /* End mouse reporting mode */
206 static char *Start_Alt_Chars_Str
; /* as */
207 static char *End_Alt_Chars_Str
; /* ae */
208 static char *Enable_Alt_Char_Set
; /* eA */
210 static char *Term_Init_Str
;
211 static char *Keypad_Init_Str
;
212 static char *Term_Reset_Str
;
213 static char *Keypad_Reset_Str
;
215 /* status line functions */
216 static char *Disable_Status_line_Str
; /* ds */
217 static char *Return_From_Status_Line_Str
; /* fs */
218 static char *Goto_Status_Line_Str
; /* ts */
219 static int Num_Status_Line_Columns
; /* ws */
220 /* static int Status_Line_Esc_Ok; */ /* es */
222 /* static int Len_Curs_F_Str = 5; */
224 /* cm string has %i%d since termcap numbers columns from 0 */
225 /* char *CURS_POS_STR = "\033[%d;%df"; ansi-- hor and vert pos */
226 static char *Curs_Pos_Str
; /* = "\033[%i%d;%dH";*/ /* cm termcap string */
228 /* scrolling region */
229 static int Scroll_r1
= 0, Scroll_r2
= 23;
230 static int Cursor_r
, Cursor_c
; /* 0 based */
232 /* current attributes --- initialized to impossible value */
233 static SLtt_Char_Type Current_Fgbg
= 0xFFFFFFFFU
;
235 static int Cursor_Set
; /* 1 if cursor position known, 0
236 * if not. -1 if only row is known
239 #define MAX_OUTPUT_BUFFER_SIZE 4096
241 static unsigned char Output_Buffer
[MAX_OUTPUT_BUFFER_SIZE
];
242 static unsigned char *Output_Bufferp
= Output_Buffer
;
244 unsigned long SLtt_Num_Chars_Output
;
246 int _pSLusleep (unsigned long usecs
)
248 #if !defined(VMS) || (__VMS_VER >= 70000000)
250 tv
.tv_sec
= usecs
/ 1000000;
251 tv
.tv_usec
= usecs
% 1000000;
252 return select(0, NULL
, NULL
, NULL
, &tv
);
258 int SLtt_flush_output (void)
262 int n
= (int) (Output_Bufferp
- Output_Buffer
);
264 SLtt_Num_Chars_Output
+= n
;
269 nwrite
= write (SLang_TT_Write_FD
, (char *) Output_Buffer
+ total
, n
);
276 _pSLusleep (100000); /* 1/10 sec */
281 if (errno
== EWOULDBLOCK
)
288 if (errno
== EINTR
) continue;
295 Output_Bufferp
= Output_Buffer
;
300 static void tt_write(char *str
, unsigned int n
)
302 static unsigned long last_time
;
307 if ((str
== NULL
) || (n
== 0)) return;
312 ndiff
= MAX_OUTPUT_BUFFER_SIZE
- (int) (Output_Bufferp
- Output_Buffer
);
315 SLMEMCPY ((char *) Output_Bufferp
, str
, ndiff
);
316 Output_Bufferp
+= ndiff
;
317 SLtt_flush_output ();
323 SLMEMCPY ((char *) Output_Bufferp
, str
, n
);
329 if (((SLtt_Baud_Rate
> 150) && (SLtt_Baud_Rate
<= 9600))
330 && (10 * total
> SLtt_Baud_Rate
))
333 if ((now
= (unsigned long) time(NULL
)) - last_time
<= 1)
335 SLtt_flush_output ();
342 static void tt_write_string (char *str
)
344 if (str
!= NULL
) tt_write(str
, strlen(str
));
347 void SLtt_write_string (char *str
)
349 tt_write_string (str
);
353 void SLtt_putchar (char ch
)
355 SLtt_normal_video ();
358 if (ch
>= ' ') Cursor_c
++;
359 else if (ch
== '\b') Cursor_c
--;
360 else if (ch
== '\r') Cursor_c
= 0;
363 if ((Cursor_c
+ 1 == SLtt_Screen_Cols
)
364 && Automatic_Margins
) Cursor_Set
= 0;
367 if (Output_Bufferp
< Output_Buffer
+ MAX_OUTPUT_BUFFER_SIZE
)
369 *Output_Bufferp
++ = (unsigned char) ch
;
371 else tt_write (&ch
, 1);
374 static unsigned int tt_sprintf(char *buf
, unsigned int buflen
, char *fmt
, int x
, int y
)
377 unsigned char *b
, *bmax
, ch
;
379 int z
, z1
, parse_level
;
384 unsigned int stack_len
;
386 #define STACK_POP (stack_len ? stack[--stack_len] : 0)
394 stack
[0] = y
; /* pushed for termcap */
398 parms
[1] = x
; /* p1 */
399 parms
[2] = y
; /* p2 */
405 b
= (unsigned char *) buf
;
408 fmt_max
= fmt
+ strlen (fmt
);
410 while ((fmt
< fmt_max
) && (b
< bmax
))
420 if (fmt
== fmt_max
) break;
431 if (fmt
== fmt_max
) break;
433 if ((ch
>= '0') && (ch
<= '9'))
434 stack
[stack_len
++] = parms
[ch
- '0'];
438 if (fmt
== fmt_max
) break;
439 stack
[stack_len
++] = *fmt
++;
440 if (fmt
< fmt_max
) fmt
++; /* skip ' */
443 case '{': /* literal constant, e.g. {30} */
445 while ((fmt
< fmt_max
) && ((ch
= *fmt
) <= '9') && (ch
>= '0'))
447 z
= z
* 10 + (ch
- '0');
450 stack
[stack_len
++] = z
;
451 if ((ch
== '}') && (fmt
< fmt_max
)) fmt
++;
455 if (fmt
== fmt_max
) break;
457 if ((ch
!= '2') && (ch
!= '3'))
465 if (fmt
== fmt_max
) break;
471 x_fmt_buf_ptr
= x_fmt_buf
;
472 if (zero_pad
) *x_fmt_buf_ptr
++ = '0';
473 *x_fmt_buf_ptr
++ = ch
;
474 *x_fmt_buf_ptr
++ = 'X';
480 sprintf ((char *)b
, x_fmt_buf
, z
);
481 b
+= strlen ((char *)b
);
486 field_width
= (ch
- '0');
494 *b
++ = z
/ 100 + '0';
499 else if (zero_pad
&& (field_width
== 3))
502 if (b
== bmax
) break;
508 else if (zero_pad
&& (field_width
>= 2))
511 if (b
== bmax
) break;
513 field_width
= zero_pad
= 0;
521 sprintf ((char *) b
, "%X", z
);
522 b
+= strlen ((char *)b
);
530 /* Handling this depends upon whether or not we are parsing
531 * terminfo. Terminfo requires the stack so use it as an
537 stack
[stack_len
- 1] += z
;
539 else if (fmt
< fmt_max
)
542 if ((unsigned char) ch
== 128) ch
= 0;
543 ch
= ch
+ (unsigned char) STACK_POP
;
544 if (ch
== '\n') ch
++;
549 /* Binary operators */
566 case '-': z
= (z
- z1
); break;
567 case '*': z
= (z
* z1
); break;
568 case '/': z
= (z
/ z1
); break;
569 case 'm': z
= (z
% z1
); break;
570 case '&': z
= (z
& z1
); break;
571 case '|': z
= (z
| z1
); break;
572 case '^': z
= (z
^ z1
); break;
573 case '=': z
= (z
== z1
); break;
574 case '>': z
= (z
> z1
); break;
575 case '<': z
= (z
< z1
); break;
576 case 'A': z
= (z
&& z1
); break;
577 case 'O': z
= (z
|| z1
); break;
579 stack
[stack_len
++] = z
;
585 stack
[stack_len
++] = !z
;
590 stack
[stack_len
++] = ~z
;
593 case 'r': /* termcap -- swap parameters */
595 stack
[0] = stack
[1];
599 case '.': /* termcap */
601 ch
= (unsigned char) STACK_POP
;
602 if (ch
== '\n') ch
++;
607 if (fmt
== fmt_max
) break;
609 if ((ch
>= 'a') && (ch
<= 'z'))
610 stack
[stack_len
++] = variables
[ch
- 'a'];
614 if (fmt
== fmt_max
) break;
616 if ((ch
>= 'a') && (ch
<= 'z'))
617 variables
[ch
- 'a'] = STACK_POP
;
620 /* If then else parsing. Actually, this is rather easy. The
621 * key is to notice that 'then' does all the work. 'if' simply
622 * there to indicate the start of a test and endif indicates
623 * the end of tests. If 'else' is seen, then skip to
627 case ';': /* endif */
633 break; /* good. Continue parsing. */
635 /* z == 0 and test has failed. So, skip past this entire if
636 * expression to the matching else or matching endif.
642 while (fmt
< fmt_max
)
647 if ((ch1
!= '%') || (fmt
== fmt_max
))
652 if (ch1
== '?') parse_level
++; /* new if */
655 if ((ch
!= 'e') && (parse_level
== 0))
660 if (parse_level
== 0)
672 return (unsigned int) (b
- (unsigned char *) buf
);
675 static void tt_printf(char *fmt
, int x
, int y
)
679 if (fmt
== NULL
) return;
680 n
= tt_sprintf(buf
, sizeof (buf
), fmt
, x
, y
);
684 void SLtt_set_scroll_region (int r1
, int r2
)
688 tt_printf (Scroll_R_Str
, Scroll_r1
, Scroll_r2
);
692 void SLtt_reset_scroll_region (void)
694 SLtt_set_scroll_region(0, SLtt_Screen_Rows
- 1);
697 int SLtt_set_cursor_visibility (int show
)
699 if ((Cursor_Visible_Str
== NULL
) || (Cursor_Invisible_Str
== NULL
))
702 tt_write_string (show
? Cursor_Visible_Str
: Cursor_Invisible_Str
);
706 /* the goto_rc function moves to row relative to scrolling region */
707 void SLtt_goto_rc(int r
, int c
)
713 if ((c
< 0) || (r
< 0))
719 /* if (No_Move_In_Standout && Current_Fgbg) SLtt_normal_video (); */
722 if ((Cursor_Set
> 0) || ((Cursor_Set
< 0) && !Automatic_Margins
))
725 if ((n
== -1) && (Cursor_Set
> 0) && (Cursor_c
== c
)
726 && (Curs_Up_Str
!= NULL
))
730 else if ((n
>= 0) && (n
<= 4))
732 if ((n
== 0) && (Cursor_Set
== 1)
733 && ((c
> 1) || (c
== Cursor_c
)))
735 if (Cursor_c
== c
) return;
736 if (Cursor_c
== c
+ 1)
738 /* cursor movement optimizations, like backspace
739 doesn't work as needed on qansi-m consoles when
740 current table is not a G0, so we'll disable it. */
749 /* do the generic cursor positioning,
750 without an optimization */
755 else if ((c
== 0) && (!QANSI_Console
)) /* the same things
756 for the qansi-m console limitation */
759 if ((Cursor_Set
!= 1) || (Cursor_c
!= 0)) *s
++ = '\r';
760 while (n
--) *s
++ = '\n';
762 /* Need to add this after \n to start a new record. Sheesh. */
768 /* Will fail on VMS */
770 else if ((SLtt_Newline_Ok
&& (Cursor_Set
== 1) &&
771 (Cursor_c
>= c
) && (c
+ 3 > Cursor_c
)) &&
775 while (n
--) *s
++ = '\n';
777 while (n
--) *s
++ = '\b';
784 if (s
!= NULL
) tt_write_string(s
);
785 else tt_printf(Curs_Pos_Str
, r
, c
);
786 Cursor_c
= c
; Cursor_r
= r
;
790 void SLtt_begin_insert (void)
792 tt_write_string(Ins_Mode_Str
);
795 void SLtt_end_insert (void)
797 tt_write_string(Eins_Mode_Str
);
800 void SLtt_delete_char (void)
802 SLtt_normal_video ();
803 tt_write_string(Del_Char_Str
);
806 void SLtt_erase_line (void)
809 Cursor_Set
= 1; Cursor_c
= 0;
811 /* Put the cursor back at the beginning of the line */
813 Cursor_Set
= 1; Cursor_c
= 0;
816 /* It appears that the Linux console, and most likely others do not
817 * like scrolling regions that consist of one line. So I have to
818 * resort to this stupidity to make up for that stupidity.
820 static void delete_line_in_scroll_region (void)
822 SLtt_goto_rc (Cursor_r
- Scroll_r1
, 0);
826 void SLtt_delete_nlines (int nn
)
832 n
= (unsigned int) nn
;
834 SLtt_normal_video ();
836 if (Scroll_r1
== Scroll_r2
)
838 delete_line_in_scroll_region ();
842 if (Del_N_Lines_Str
!= NULL
) tt_printf(Del_N_Lines_Str
, n
, 0);
844 /* get a new terminal */
849 if (dn
> sizeof (buf
))
852 SLMEMSET (buf
, '\n', dn
);
862 SLtt_set_scroll_region(curs
, Scroll_r2
);
863 SLtt_goto_rc(Scroll_r2
- Scroll_r1
, 0);
864 SLMEMSET(buf
, '\n', (unsigned int) n
);
865 tt_write(buf
, (unsigned int) n
);
866 /* while (n--) tt_putchar('\n'); */
867 SLtt_set_scroll_region(r1
, Scroll_r2
);
868 SLtt_goto_rc(curs
, 0);
874 /* If the terminal is a color terminal but the user wants black and
875 * white, then make sure that the colors are reset. This appears to be
878 if ((SLtt_Use_Ansi_Colors
== 0) && Is_Color_Terminal
)
880 if (Reset_Color_String
!= NULL
)
881 tt_write_string (Reset_Color_String
);
883 tt_write ("\033[0m\033[m", 7);
887 SLtt_reset_scroll_region ();
888 tt_write_string(Cls_Str
);
891 void SLtt_reverse_index (int n
)
897 if (Scroll_r1
== Scroll_r2
)
899 delete_line_in_scroll_region ();
903 if (Add_N_Lines_Str
!= NULL
) tt_printf(Add_N_Lines_Str
,n
, 0);
906 while(n
--) tt_write_string(Rev_Scroll_Str
);
910 int SLtt_Ignore_Beep
= 1;
911 static char *Visible_Bell_Str
;
913 void SLtt_beep (void)
915 if (SLtt_Ignore_Beep
& 0x1) SLtt_putchar('\007');
917 if (SLtt_Ignore_Beep
& 0x2)
919 if (Visible_Bell_Str
!= NULL
) tt_write_string (Visible_Bell_Str
);
921 else if (Linux_Console
)
923 tt_write ("\033[?5h", 5);
924 SLtt_flush_output ();
926 tt_write ("\033[?5l", 5);
930 SLtt_flush_output ();
933 static void write_string_with_care (char *);
935 static void del_eol (void)
940 if ((Del_Eol_Str
!= NULL
)
941 && (Can_Background_Color_Erase
|| ((Current_Fgbg
& ~0xFF) == 0)))
943 tt_write_string(Del_Eol_Str
);
950 /* Avoid writing to the lower right corner. If the terminal does not
951 * have Del_Eol_Str, then it probably does not have what it takes to play
952 * games with insert-mode to "push" the desired character into that corner.
954 if (Cursor_r
+ 1 < SLtt_Screen_Rows
)
957 while (c
< SLtt_Screen_Cols
)
962 Cursor_c
= (SLtt_Screen_Cols
-1);
964 while (Cursor_c
< SLtt_Screen_Cols
)
966 write_string_with_care (" ");
969 Cursor_c
= SLtt_Screen_Cols
- 1;
974 void SLtt_del_eol (void)
976 if (Current_Fgbg
!= 0xFFFFFFFFU
) SLtt_normal_video ();
980 typedef SLCONST
struct
983 SLtt_Char_Type color
;
987 #define MAX_COLOR_NAMES 17
988 static Color_Def_Type Color_Defs
[MAX_COLOR_NAMES
] =
990 {"black", SLSMG_COLOR_BLACK
},
991 {"red", SLSMG_COLOR_RED
},
992 {"green", SLSMG_COLOR_GREEN
},
993 {"brown", SLSMG_COLOR_BROWN
},
994 {"blue", SLSMG_COLOR_BLUE
},
995 {"magenta", SLSMG_COLOR_MAGENTA
},
996 {"cyan", SLSMG_COLOR_CYAN
},
997 {"lightgray", SLSMG_COLOR_LGRAY
},
998 {"gray", SLSMG_COLOR_GRAY
},
999 {"brightred", SLSMG_COLOR_BRIGHT_RED
},
1000 {"brightgreen", SLSMG_COLOR_BRIGHT_GREEN
},
1001 {"yellow", SLSMG_COLOR_BRIGHT_BROWN
},
1002 {"brightblue", SLSMG_COLOR_BRIGHT_BLUE
},
1003 {"brightmagenta", SLSMG_COLOR_BRIGHT_CYAN
},
1004 {"brightcyan", SLSMG_COLOR_BRIGHT_MAGENTA
},
1005 {"white", SLSMG_COLOR_BRIGHT_WHITE
},
1006 #define SLSMG_COLOR_DEFAULT 0xFF
1007 {"default", SLSMG_COLOR_DEFAULT
}
1010 static int Brushes_Initialized
= 0;
1012 static int initialize_brushes (void)
1015 Brush_Info_Type
*b
, *bmax
;
1018 bmax
= b
+ JMAX_COLORS
;
1028 b
->fgbg
= MAKE_COLOR(fg
,bg
);
1029 b
->mono
= SLTT_REV_MASK
;
1041 Brush_Table
[0].mono
= 0;
1042 Brushes_Initialized
= 1;
1047 static Brush_Info_Type
*get_brush_info (unsigned int color
)
1049 if (Brushes_Initialized
== 0)
1050 initialize_brushes ();
1052 color
&= SLSMG_COLOR_MASK
;
1054 if (color
>= JMAX_COLORS
)
1057 return Brush_Table
+ color
;
1060 static SLtt_Char_Type
get_brush_attr (unsigned int color
)
1064 if (NULL
== (b
= get_brush_info (color
)))
1065 return (SLtt_Char_Type
)-1;
1067 if (SLtt_Use_Ansi_Colors
)
1073 static SLtt_Char_Type
get_brush_fgbg (unsigned int color
)
1075 return get_brush_info(color
)->fgbg
;
1078 int SLtt_set_mono (int obj
, char *what
, SLtt_Char_Type mask
)
1083 if (NULL
== (b
= get_brush_info (obj
)))
1086 b
->mono
= mask
& ATTR_MASK
;
1090 static char *check_color_for_digit_form (char *color
)
1092 unsigned int i
, ich
;
1093 unsigned char *s
= (unsigned char *) color
;
1096 while ((ich
= (unsigned int) *s
) != 0)
1098 if ((ich
< '0') || (ich
> '9'))
1101 i
= i
* 10 + (ich
- '0');
1105 if (i
< MAX_COLOR_NAMES
)
1106 color
= Color_Defs
[i
].name
;
1111 static int get_default_colors (char **fgp
, char **bgp
)
1113 static char fg_buf
[16], bg_buf
[16], *bg
, *fg
;
1114 static int already_parsed
;
1117 if (already_parsed
== -1)
1127 already_parsed
= -1;
1129 bg
= getenv ("COLORFGBG");
1133 bg
= getenv ("DEFAULT_COLORS");
1139 pmax
= p
+ (sizeof (fg_buf
) - 1);
1141 while ((*bg
!= 0) && (*bg
!= ';'))
1143 if (p
< pmax
) *p
++ = *bg
;
1151 pmax
= p
+ (sizeof (bg_buf
) - 1);
1153 /* Mark suggested allowing for extra application specific stuff following
1154 * the background color. That is what the check for the semi-colon is for.
1156 while ((*bg
!= 0) && (*bg
!= ';'))
1158 if (p
< pmax
) *p
++ = *bg
;
1163 if (!strcmp (fg_buf
, "default") || !strcmp(bg_buf
, "default"))
1165 *fgp
= *bgp
= fg
= bg
= "default";
1169 *fgp
= fg
= check_color_for_digit_form (fg_buf
);
1170 *bgp
= bg
= check_color_for_digit_form (bg_buf
);
1176 static int Color_0_Modified
= 0;
1178 int SLtt_set_color_object (int obj
, SLtt_Char_Type attr
)
1182 if (NULL
== (b
= get_brush_info (obj
)))
1186 if (obj
== 0) Color_0_Modified
= 1;
1188 if (_pSLtt_color_changed_hook
!= NULL
)
1189 (*_pSLtt_color_changed_hook
)();
1194 SLtt_Char_Type
SLtt_get_color_object (int obj
)
1196 return get_brush_fgbg (obj
);
1199 int SLtt_add_color_attribute (int obj
, SLtt_Char_Type attr
)
1203 if (NULL
== (b
= get_brush_info (obj
)))
1206 b
->fgbg
|= (attr
& ATTR_MASK
);
1208 if (obj
== 0) Color_0_Modified
= 1;
1209 if (_pSLtt_color_changed_hook
!= NULL
)
1210 (*_pSLtt_color_changed_hook
)();
1215 static SLtt_Char_Type
fb_to_fgbg (SLtt_Char_Type f
, SLtt_Char_Type b
)
1217 SLtt_Char_Type attr
;
1219 if (Max_Terminfo_Colors
!= 8)
1221 if (f
!= SLSMG_COLOR_DEFAULT
) f
%= Max_Terminfo_Colors
;
1222 if (b
!= SLSMG_COLOR_DEFAULT
) b
%= Max_Terminfo_Colors
;
1223 return ((f
<< 8) | (b
<< 16));
1226 /* Otherwise we have 8 ansi colors. Try to get bright versions
1227 * by using the BOLD and BLINK attributes.
1232 /* Note: If f represents default, it will have the value 0xFF */
1233 if (f
!= SLSMG_COLOR_DEFAULT
)
1235 if (f
& 0x8) attr
= SLTT_BOLD_MASK
;
1239 if (b
!= SLSMG_COLOR_DEFAULT
)
1241 if (b
& 0x8) attr
|= SLTT_BLINK_MASK
;
1245 return ((f
<< 8) | (b
<< 16) | attr
);
1248 /* This looks for colors with name form 'colorN'. If color is of this
1249 * form, N is passed back via parameter list.
1251 static int parse_color_digit_name (char *color
, SLtt_Char_Type
*f
)
1256 if (strncmp (color
, "color", 5))
1268 ch
= (unsigned char) *color
++;
1271 if ((ch
> '9') || (ch
< '0'))
1274 if (i
> 0xFFFFFFFFU
/ 10)
1282 *f
= (SLtt_Char_Type
) i
;
1286 static int make_color_fgbg (char *fg
, char *bg
, SLtt_Char_Type
*fgbg
)
1288 SLtt_Char_Type f
= 0xFFFFFFFFU
, b
= 0xFFFFFFFFU
;
1292 if ((fg
!= NULL
) && (*fg
== 0)) fg
= NULL
;
1293 if ((bg
!= NULL
) && (*bg
== 0)) bg
= NULL
;
1295 if ((fg
== NULL
) || (bg
== NULL
))
1297 if (-1 == get_default_colors (&dfg
, &dbg
))
1300 if (fg
== NULL
) fg
= dfg
;
1301 if (bg
== NULL
) bg
= dbg
;
1304 if (-1 == parse_color_digit_name (fg
, &f
))
1306 for (i
= 0; i
< MAX_COLOR_NAMES
; i
++)
1308 if (strcmp(fg
, Color_Defs
[i
].name
)) continue;
1309 f
= Color_Defs
[i
].color
;
1314 if (-1 == parse_color_digit_name (bg
, &b
))
1316 for (i
= 0; i
< MAX_COLOR_NAMES
; i
++)
1318 if (strcmp(bg
, Color_Defs
[i
].name
)) continue;
1319 b
= Color_Defs
[i
].color
;
1324 if ((f
== 0xFFFFFFFFU
) || (b
== 0xFFFFFFFFU
))
1327 *fgbg
= fb_to_fgbg (f
, b
);
1331 int SLtt_set_color (int obj
, char *what
, char *fg
, char *bg
)
1333 SLtt_Char_Type fgbg
;
1337 if (-1 == make_color_fgbg (fg
, bg
, &fgbg
))
1340 return SLtt_set_color_object (obj
, fgbg
);
1343 int SLtt_set_color_fgbg (int obj
, SLtt_Char_Type f
, SLtt_Char_Type b
)
1345 return SLtt_set_color_object (obj
, fb_to_fgbg (f
, b
));
1348 void SLtt_set_alt_char_set (int i
)
1351 if (SLtt_Has_Alt_Charset
== 0) return;
1355 if (i
== last_i
) return;
1356 tt_write_string (i
? Start_Alt_Chars_Str
: End_Alt_Chars_Str
);
1360 static void write_attributes (SLtt_Char_Type fgbg
)
1363 int unknown_attributes
;
1365 if (Worthless_Highlight
) return;
1366 if (fgbg
== Current_Fgbg
) return;
1368 unknown_attributes
= 0;
1370 /* Before spitting out colors, fix attributes */
1371 if ((fgbg
& ATTR_MASK
) != (Current_Fgbg
& ATTR_MASK
))
1373 if (Current_Fgbg
& ATTR_MASK
)
1375 tt_write_string(Norm_Vid_Str
);
1376 /* In case normal video turns off ALL attributes: */
1377 if (fgbg
& SLTT_ALTC_MASK
)
1378 Current_Fgbg
&= ~SLTT_ALTC_MASK
;
1379 SLtt_set_alt_char_set (0);
1382 if ((fgbg
& SLTT_ALTC_MASK
)
1383 != (Current_Fgbg
& SLTT_ALTC_MASK
))
1385 SLtt_set_alt_char_set ((int) (fgbg
& SLTT_ALTC_MASK
));
1388 if (fgbg
& SLTT_ULINE_MASK
) tt_write_string (UnderLine_Vid_Str
);
1389 if (fgbg
& SLTT_BOLD_MASK
) SLtt_bold_video ();
1390 if (fgbg
& SLTT_REV_MASK
) tt_write_string (Rev_Vid_Str
);
1391 if (fgbg
& SLTT_BLINK_MASK
)
1393 /* Someday Linux will have a blink mode that set high intensity
1394 * background. Lets be prepared.
1396 if (SLtt_Blink_Mode
) tt_write_string (Blink_Vid_Str
);
1398 unknown_attributes
= 1;
1401 if (SLtt_Use_Ansi_Colors
)
1403 fg0
= (int) GET_FG(fgbg
);
1404 bg0
= (int) GET_BG(fgbg
);
1406 if (unknown_attributes
1407 || (fg0
!= (int)GET_FG(Current_Fgbg
)))
1409 if (fg0
== SLSMG_COLOR_DEFAULT
)
1410 tt_write_string (Default_Color_Fg_Str
);
1412 tt_printf (Color_Fg_Str
, COLOR_ARG(fg0
, Is_Bg_BGR
), 0);
1415 if (unknown_attributes
1416 || (bg0
!= (int)GET_BG(Current_Fgbg
)))
1418 if (bg0
== SLSMG_COLOR_DEFAULT
)
1419 tt_write_string (Default_Color_Bg_Str
);
1421 tt_printf (Color_Bg_Str
, COLOR_ARG(bg0
, Is_Bg_BGR
), 0);
1425 Current_Fgbg
= fgbg
;
1428 static int Video_Initialized
;
1430 void SLtt_reverse_video (int color
)
1432 SLtt_Char_Type fgbg
;
1434 if (Worthless_Highlight
) return;
1436 if (Video_Initialized
== 0)
1438 if (color
== JNORMAL_COLOR
)
1440 tt_write_string (Norm_Vid_Str
);
1442 else tt_write_string (Rev_Vid_Str
);
1443 Current_Fgbg
= 0xFFFFFFFFU
;
1447 fgbg
= get_brush_attr (color
);
1449 if (fgbg
== Current_Fgbg
) return;
1450 write_attributes (fgbg
);
1453 void SLtt_normal_video (void)
1455 SLtt_reverse_video(JNORMAL_COLOR
);
1458 void SLtt_narrow_width (void)
1460 tt_write ("\033[?3l", 5);
1463 void SLtt_wide_width (void)
1465 tt_write ("\033[?3h", 5);
1468 /* Highest bit represents the character set. */
1469 #define COLOR_OF(a) ((a)->color & SLSMG_COLOR_MASK)
1471 static int bce_color_eqs (SLsmg_Char_Type
*a
, SLsmg_Char_Type
*b
)
1473 SLsmg_Color_Type ca
, cb
;
1474 Brush_Info_Type
*ba
, *bb
;
1482 ba
= get_brush_info (ca
);
1483 bb
= get_brush_info (cb
);
1485 if (SLtt_Use_Ansi_Colors
== 0)
1486 return ba
->mono
== bb
->mono
;
1488 if (Bce_Color_Offset
== 0)
1489 return ba
->fgbg
== bb
->fgbg
;
1491 /* If either are color 0, then we do not know what that means since the
1492 * terminal does not support BCE */
1493 if ((ca
== 0) || (cb
== 0))
1496 return get_brush_fgbg (ca
-1) == get_brush_fgbg(cb
-1);
1499 /* The whole point of this routine is to prevent writing to the last column
1500 * and last row on terminals with automatic margins.
1502 static void write_string_with_care (char *str
)
1506 if (str
== NULL
) return;
1509 if (Automatic_Margins
&& (Cursor_r
+ 1 == SLtt_Screen_Rows
))
1511 if (_pSLtt_UTF8_Mode
== 0)
1513 if (len
+ (unsigned int) Cursor_c
>= (unsigned int) SLtt_Screen_Cols
)
1515 /* For now, just do not write there. Later, something more
1516 * sophisticated will be implemented.
1518 if (SLtt_Screen_Cols
> Cursor_c
)
1519 len
= SLtt_Screen_Cols
- Cursor_c
- 1;
1526 unsigned int nchars
= SLutf8_strlen((SLuchar_Type
*)str
, 1);
1527 if (nchars
+ (unsigned int) Cursor_c
>= (unsigned int) SLtt_Screen_Cols
)
1529 if (SLtt_Screen_Cols
> Cursor_c
)
1532 nchars
= SLtt_Screen_Cols
- Cursor_c
- 1;
1533 p
= (char *)SLutf8_skip_chars((SLuchar_Type
*) str
, (SLuchar_Type
*)(str
+ len
), nchars
, NULL
, 1);
1541 tt_write (str
, len
);
1544 static void send_attr_str (SLsmg_Char_Type
*s
, SLsmg_Char_Type
*smax
)
1546 unsigned char out
[1+SLUTF8_MAX_MBLEN
*SLSMG_MAX_CHARS_PER_CELL
*SLTT_MAX_SCREEN_COLS
];
1547 unsigned char *p
, *pmax
;
1548 register SLtt_Char_Type attr
;
1549 SLsmg_Color_Type color
, last_color
= (SLsmg_Color_Type
)-1;
1553 pmax
= p
+ (sizeof (out
)-1);
1559 unsigned int nchars
;
1561 if (0 == (nchars
= s
->nchars
))
1563 /* 2nd element of a char that occupies two columns */
1565 if (_pSLtt_UTF8_Mode
== 0)
1573 #if SLTT_HAS_NON_BCE_SUPPORT
1574 if (Bce_Color_Offset
1575 && (color
>= Bce_Color_Offset
))
1576 color
-= Bce_Color_Offset
;
1581 if (color
!= last_color
)
1583 attr
= get_brush_attr (color
);
1585 if (color
& SLSMG_ACS_MASK
) /* alternate char set */
1587 if (SLtt_Use_Blink_For_ACS
)
1589 if (SLtt_Blink_Mode
) attr
|= SLTT_BLINK_MASK
;
1591 else attr
|= SLTT_ALTC_MASK
;
1594 if (attr
!= Current_Fgbg
)
1598 /* it is a space so only consider it different if it
1599 * has different attributes.
1601 || (attr
!= Current_Fgbg
)
1607 write_string_with_care ((char *) out
);
1609 Cursor_c
+= dcursor_c
;
1612 write_attributes (attr
);
1618 if ((wch
< 0x80) && (nchars
== 1))
1619 *p
++ = (unsigned char) wch
;
1620 else if (_pSLtt_UTF8_Mode
== 0)
1624 else if (wch
< (SLwchar_Type
)SLsmg_Display_Eight_Bit
)
1626 *p
++ = (unsigned char) wch
;
1631 for (i
= 0; i
< nchars
; i
++)
1633 if (NULL
== (p
= SLutf8_encode (s
->wchars
[i
], p
, pmax
-p
)))
1635 fprintf (stderr
, "*** send_attr_str: buffer too small\n");
1644 if (p
!= out
) write_string_with_care ((char *) out
);
1645 Cursor_c
+= dcursor_c
;
1648 static void forward_cursor (unsigned int n
, int row
)
1653 /* if (Current_Fgbg & ~0xFF) */
1655 /* unsigned int num = 0; */
1656 /* while (num < n) */
1658 /* write_string_with_care (" "); */
1661 /* Cursor_c += n; */
1668 SLtt_normal_video ();
1670 if (n
>= sizeof (buf
))
1671 n
= sizeof (buf
) - 1;
1673 SLMEMSET (buf
, ' ', n
);
1675 write_string_with_care (buf
);
1678 else if (Curs_F_Str
!= NULL
)
1681 n
= tt_sprintf(buf
, sizeof (buf
), Curs_F_Str
, (int) n
, 0);
1684 else SLtt_goto_rc (row
, (int) (Cursor_c
+ n
));
1688 /* FIXME!! If the terminal does not support color, then this route has
1689 * problems of color object 0 has been assigned some monochrome attribute
1690 * such as reverse video. In such a case, space_char=' ' is not a simple
1691 * space character as is assumed below.
1694 #define COLOR_EQS(a,b) ((COLOR_OF(a)==COLOR_OF(b)) || bce_color_eqs (a,b))
1695 #define CHARSET(a) ((a)->color&SLSMG_ACS_MASK)
1696 #define CHAR_EQS(a, b) (((a)->nchars==(b)->nchars) \
1697 && (((a)->nchars == 0) \
1698 || ((((a)->wchars[0]==(b)->wchars[0]) \
1699 && (0 == memcmp((a)->wchars, (b)->wchars, (a)->nchars*sizeof(SLwchar_Type)))) \
1700 && (COLOR_EQS(a,b)) \
1701 && (CHARSET(a)==CHARSET(b)))))
1703 #define CHAR_EQS_SPACE(a) (((a)->wchars[0]==' ') && ((a)->color==0) && ((a)->nchars==1))
1705 void SLtt_smart_puts(SLsmg_Char_Type
*neww
, SLsmg_Char_Type
*oldd
, int len
, int row
)
1707 register SLsmg_Char_Type
*p
, *q
, *qmax
, *pmax
, *buf
;
1708 SLsmg_Char_Type buffer
[SLTT_MAX_SCREEN_COLS
+1];
1709 unsigned int n_spaces
;
1710 SLsmg_Char_Type
*space_match
, *last_buffered_match
;
1711 #ifdef HP_GLITCH_CODE
1712 int handle_hp_glitch
= 0;
1714 SLsmg_Char_Type
*space_char
;
1715 SLsmg_Char_Type space_char_buf
;
1717 #define SLTT_USE_INSERT_HACK 1
1718 #if SLTT_USE_INSERT_HACK
1719 SLsmg_Char_Type
*insert_hack_prev
= NULL
;
1720 SLsmg_Char_Type
*insert_hack_char
= NULL
;
1722 if ((row
+ 1 == SLtt_Screen_Rows
)
1723 && (len
== SLtt_Screen_Cols
)
1725 && (SLtt_Term_Cannot_Insert
== 0)
1726 && Automatic_Margins
)
1728 SLsmg_Char_Type
*a
, *b
;
1729 insert_hack_char
= &neww
[len
-1];
1735 insert_hack_char
= NULL
;
1737 insert_hack_prev
= &neww
[len
-2];
1741 memset ((char *) &space_char_buf
, 0, sizeof (SLsmg_Char_Type
));
1742 space_char
= &space_char_buf
;
1743 space_char
->nchars
= 1;
1744 space_char
->wchars
[0] = ' ';
1746 if (len
> SLTT_MAX_SCREEN_COLS
)
1747 len
= SLTT_MAX_SCREEN_COLS
;
1753 /* Find out where to begin --- while they match, we are ok */
1756 if (q
== qmax
) return;
1758 #if SLANG_HAS_KANJI_SUPPORT
1760 { /* new is kanji */
1761 if ((*q
& 0x80) && ((q
+ 1) < qmax
))
1762 { /* old is also kanji */
1763 if (((0xFF & *q
) != (0xFF & *p
))
1764 || ((0xFF & q
[1]) != (0xFF & p
[1])))
1765 break; /* both kanji, but not match */
1768 { /* kanji match ! */
1769 if (!COLOR_EQS(*q
, *p
)) break;
1771 if (!COLOR_EQS(*q
, *p
)) break;
1777 else break; /* old is not kanji */
1780 { /* new is not kanji */
1781 if (*q
& 0x80) break; /* old is kanji */
1784 if (!CHAR_EQS(q
, p
)) break;
1788 #ifdef HP_GLITCH_CODE
1791 SLsmg_Char_Type
*qq
= q
;
1793 SLtt_goto_rc (row
, (int) (p
- neww
));
1799 SLtt_normal_video ();
1802 handle_hp_glitch
= 1;
1809 /* Find where the last non-blank character on old/new screen is */
1811 if (CHAR_EQS_SPACE(pmax
-1))
1813 /* If we get here, then we can erase to the end of the line to create
1814 * the final space. However, this will only work _if_ erasing will
1815 * get us the correct color. If the terminal supports BCE, then this
1816 * is easy. If it does not, then we can only perform this operation
1817 * if the color is known via something like COLORFGBG. For now,
1818 * I just will not perform the optimization for such terminals.
1820 if ((Can_Background_Color_Erase
)
1821 && SLtt_Use_Ansi_Colors
)
1822 space_char
= pmax
- 1;
1827 if (!CHAR_EQS(pmax
, space_char
))
1838 if (!CHAR_EQS(qmax
, space_char
))
1845 last_buffered_match
= buf
= buffer
; /* buffer is empty */
1847 #ifdef HP_GLITCH_CODE
1848 if (handle_hp_glitch
)
1857 #ifdef HP_GLITCH_CODE
1858 if (Has_HP_Glitch
== 0)
1861 /* Try use use erase to bol if possible */
1862 if ((Del_Bol_Str
!= NULL
) && (CHAR_EQS_SPACE(neww
)))
1864 SLsmg_Char_Type
*p1
;
1865 SLsmg_Color_Type blank_color
= 0;
1868 if ((Can_Background_Color_Erase
)
1869 && SLtt_Use_Ansi_Colors
)
1871 SLsmg_Char_Type
*blank
= p1
;
1872 blank_color
= COLOR_OF(blank
);
1873 while ((p1
< pmax
) && (CHAR_EQS (p1
, blank
)))
1878 /* black+white attributes do not support bce */
1879 while ((p1
< pmax
) && (CHAR_EQS_SPACE (p1
)))
1883 /* Is this optimization worth it? Assume Del_Bol_Str is ESC [ 1 K
1884 * It costs 4 chars + the space needed to properly position the
1885 * cursor, e.g., ESC [ 10;10H. So, it costs at least 13 characters.
1887 if ((p1
> neww
+ 13)
1889 /* Avoid erasing from the end of the line */
1890 && ((p1
!= pmax
) || (pmax
< neww
+ len
)))
1892 int ofs
= (int) (p1
- neww
);
1895 SLtt_goto_rc (row
, ofs
- 1);
1896 SLtt_reverse_video (blank_color
);
1897 tt_write_string (Del_Bol_Str
);
1902 SLtt_goto_rc (row
, (int) (p
- neww
));
1905 SLtt_goto_rc (row
, (int) (p
- neww
));
1906 #ifdef HP_GLITCH_CODE
1911 /* loop using overwrite then skip algorithm until done */
1914 /* while they do not match and we do not hit a space, buffer them up */
1918 if (CHAR_EQS_SPACE(q
) && CHAR_EQS_SPACE(p
))
1920 /* If *q is not a space, we would have to overwrite it.
1921 * However, if *q is a space, then while *p is also one,
1922 * we only need to skip over the blank field.
1927 && CHAR_EQS_SPACE(q
)
1928 && CHAR_EQS_SPACE(p
))
1933 n_spaces
= (unsigned int) (p
- space_match
);
1936 #if SLANG_HAS_KANJI_SUPPORT
1937 if ((*p
& 0x80) && ((p
+ 1) < pmax
))
1938 { /* new is kanji */
1940 { /* old is also kanji */
1941 if (((0xFF & *q
) != (0xFF & *p
))
1942 || ((0xFF & q
[1]) != (0xFF & p
[1])))
1944 /* both kanji, but not match */
1951 { /* kanji match ? */
1952 if (!COLOR_EQS(*q
, *p
) || !COLOR_EQS(*(q
+1), *(p
+1)))
1954 /* code is match, but color is diff */
1960 /* really match ! */
1965 { /* old is not kanji */
1973 { /* new is not kanji */
1975 { /* old is kanji */
1985 /* Could be the second half of a double width character */
1986 if (p
->nchars
|| q
->nchars
)
1993 /* At this point, the buffer contains characters that do not match */
1994 if (buf
!= buffer
) send_attr_str (buffer
, buf
);
1998 && ((p
< pmax
) /* erase to eol will achieve this effect*/
1999 || (!CHAR_EQS_SPACE(space_char
))))/* unless space_char is not a simple space */
2001 forward_cursor (n_spaces
, row
);
2003 /* Now we overwrote what we could and cursor is placed at position
2004 * of a possible match of new and old. If this is the case, skip
2008 /* Note that from here on, the buffer will contain matched characters */
2009 #if !SLANG_HAS_KANJI_SUPPORT
2010 while ((p
< pmax
) && CHAR_EQS(p
, q
))
2019 if ((*p
& 0x80) && ((p
+ 1) < pmax
))
2020 { /* new is kanji */
2022 { /* old is also kanji */
2023 if (((0xFF & *q
) == (0xFF & *p
))
2024 && ((0xFF & q
[1]) == (0xFF & p
[1])))
2027 if (!COLOR_EQS(*q
, *p
)
2028 || !COLOR_EQS(q
[1], p
[1]))
2046 else break; /* both kanji, but not match */
2048 else break; /* old is not kanji */
2051 { /* new is not kanji */
2052 if (*q
& 0x80) break; /* old is kanji */
2053 if (!CHAR_EQS(*q
, *p
)) break;
2059 last_buffered_match
= buf
;
2060 if (p
>= pmax
) break;
2062 /* jump to new position is it is greater than 5 otherwise
2063 * let it sit in the buffer and output it later.
2065 if ((int) (buf
- buffer
) >= 5)
2067 forward_cursor ((unsigned int) (buf
- buffer
), row
);
2068 last_buffered_match
= buf
= buffer
;
2072 /* At this point we have reached the end of the new string with the
2073 * exception of space_chars hanging off the end of it, but we may not have
2074 * reached the end of the old string if they did not match.
2077 /* Here the buffer will consist only of characters that have matched */
2082 if ((buf
== last_buffered_match
)
2083 && ((int) (buf
- buffer
) >= 5))
2085 forward_cursor ((unsigned int) (buf
- buffer
), row
);
2089 send_attr_str (buffer
, buf
);
2096 SLtt_reverse_video (COLOR_OF(space_char
));
2100 #if SLTT_USE_INSERT_HACK
2101 else if (insert_hack_char
!= NULL
)
2103 SLtt_goto_rc (SLtt_Screen_Rows
-1, SLtt_Screen_Cols
-2);
2104 send_attr_str (insert_hack_char
, insert_hack_char
+1);
2105 SLtt_goto_rc (SLtt_Screen_Rows
-1, SLtt_Screen_Cols
-2);
2106 SLtt_begin_insert ();
2107 send_attr_str (insert_hack_prev
, insert_hack_prev
+1);
2112 if (Automatic_Margins
&& (Cursor_c
+ 1 >= SLtt_Screen_Cols
)) Cursor_Set
= 0;
2115 static void get_color_info (void)
2119 /* Allow easy mechanism to override inadequate termcap/terminfo files. */
2120 if (SLtt_Use_Ansi_Colors
== 0)
2121 SLtt_Use_Ansi_Colors
= (NULL
!= getenv ("COLORTERM"));
2123 if (SLtt_Use_Ansi_Colors
)
2124 Is_Color_Terminal
= 1;
2126 #if SLTT_HAS_NON_BCE_SUPPORT
2127 if (Can_Background_Color_Erase
== 0)
2128 Can_Background_Color_Erase
= (NULL
!= getenv ("COLORTERM_BCE"));
2131 if (-1 == get_default_colors (&fg
, &bg
))
2134 /* Check to see if application has already set them. */
2135 if (Color_0_Modified
)
2138 SLtt_set_color (0, NULL
, fg
, bg
);
2139 SLtt_set_color (1, NULL
, bg
, fg
);
2146 static int Termcap_Initalized
= 0;
2148 /* #define USE_TERMCAP 1 */
2150 /* Termcap based system */
2151 static char Termcap_Buf
[4096];
2152 /* static char Termcap_String_Buf[4096]; */
2153 /* static char *Termcap_String_Ptr; */
2154 extern char *tgetstr(char *, char **);
2155 extern int tgetent(char *, char *);
2156 extern int tgetnum(char *);
2157 extern int tgetflag(char *);
2160 static SLterminfo_Type
*Terminfo
;
2163 #define TGETFLAG(x) (SLtt_tgetflag(x) > 0)
2165 static char *fixup_tgetstr (char *what
)
2167 register char *w
, *w1
;
2173 /* Check for AIX brain-damage */
2177 /* lose pad info --- with today's technology, term is a loser if
2178 it is really needed */
2179 while ((*what
== '.') ||
2180 ((*what
>= '0') && (*what
<= '9'))) what
++;
2181 if (*what
== '*') what
++;
2183 /* lose terminfo padding--- looks like $<...> */
2185 while (*w
) if ((*w
++ == '$') && (*w
== '<'))
2188 while (*w
&& (*w
!= '>')) w
++;
2192 while ((*w1
++ = *w
++) != 0);
2196 if (*what
== 0) what
= NULL
;
2200 char *SLtt_tgetstr (char *cap
)
2204 char area_buf
[4096];
2207 if (Termcap_Initalized
== 0)
2211 /* tmp_area = &Termcap_String_Buf; */
2213 s
= tgetstr (cap
, &area
);
2214 if (area
> area_buf
+ sizeof(area_buf
))
2216 SLang_exit_error ("\
2217 The termcap tgetstr appears to have overflowed a buffer.\n\
2218 The integrity of this program has been violated.\n");
2221 s
= _pSLtt_tigetstr (Terminfo
, cap
);
2224 /* Do not strip pad info for alternate character set. I need to make
2225 * this more general.
2227 /* FIXME: Priority=low; */
2228 if (0 == strcmp (cap
, "ac"))
2231 s
= fixup_tgetstr (s
);
2233 if ((s
>= area_buf
) && (s
< area_buf
+ sizeof(area_buf
)))
2235 /* It looks like tgetstr placed the object in the buffer and
2236 * returned a pointer to that buffer. So, we have to make a
2239 * Yes, this introduces a leak...
2241 s
= SLmake_string (s
);
2247 int SLtt_tgetnum (char *s
)
2249 if (Termcap_Initalized
== 0)
2254 return _pSLtt_tigetnum (Terminfo
, s
);
2258 int SLtt_tgetflag (char *s
)
2260 if (Termcap_Initalized
== 0)
2263 return tgetflag (s
);
2265 return _pSLtt_tigetflag (Terminfo
, s
);
2270 int SLtt_tgetent(char *term
)
2272 return SLtt_initialize(term
) == 0;
2275 int SLtt_tputs(char *str
, int affcnt
, int (*p
)(int))
2277 while (*str
) (*p
)(*str
++);
2282 char *SLtt_tgoto(char *cap
, int col
, int row
)
2284 static char buf
[64];
2286 /* beware of overflows. 2^64 is 20 bytes printed */
2287 if (strlen(cap
) > 23)
2288 strcpy(buf
, "capability too long");
2290 tt_sprintf(buf
, cap
, row
, col
);
2295 static int Vt100_Like
= 0;
2297 void SLtt_get_terminfo (void)
2302 term
= getenv ("TERM");
2304 SLang_exit_error("TERM environment variable needs set.");
2306 if (0 == (status
= SLtt_initialize (term
)))
2311 SLang_exit_error ("Unknown terminal: %s\n\
2312 Check the TERM environment variable.\n\
2313 Also make sure that the terminal is defined in the terminfo database.\n\
2314 Alternatively, set the TERMCAP environment variable to the desired\n\
2321 SLang_exit_error ("\
2322 Your terminal lacks the ability to clear the screen or position the cursor.\n");
2326 /* Returns 0 if all goes well, -1 if terminal capabilities cannot be deduced,
2327 * or -2 if terminal cannot position the cursor.
2329 int SLtt_initialize (char *term
)
2335 if (_pSLtt_UTF8_Mode
== -1)
2336 _pSLtt_UTF8_Mode
= _pSLutf8_mode
;
2338 if (SLang_TT_Write_FD
== -1)
2340 /* Apparantly, this cannot fail according to the man pages. */
2341 SLang_TT_Write_FD
= fileno (stdout
);
2346 term
= getenv ("TERM");
2351 if (_pSLsecure_issetugid ()
2352 && ((term
[0] == '.') || (NULL
!= strchr(term
, '/'))))
2355 Linux_Console
= (!strncmp (term
, "linux", 5)
2357 || !strncmp(term
, "con", 3)
2361 QANSI_Console
= !strncmp (term
, "qansi-m", 7);
2365 if (strcmp(t
, "vt52") && (*t
++ == 'v') && (*t
++ == 't')
2366 && (ch
= *t
, (ch
>= '1') && (ch
<= '9'))) Vt100_Like
= 1;
2368 is_xterm
= ((0 == strncmp (term
, "xterm", 5))
2369 || (0 == strncmp (term
, "rxvt", 4))
2370 || (0 == strncmp (term
, "Eterm", 5)));
2372 almost_vtxxx
= (Vt100_Like
2375 || !strcmp (term
, "screen"));
2377 # ifndef USE_TERMCAP
2378 if (NULL
== (Terminfo
= _pSLtt_tigetent (term
)))
2380 if (almost_vtxxx
) /* Special cases. */
2383 if (!strcmp (term
, "vt100")) vt102
= 0;
2385 SLtt_set_term_vtxxx (&vt102
);
2386 (void) SLtt_get_screen_size ();
2391 # else /* USE_TERMCAP */
2392 if (1 != tgetent(Termcap_Buf
, term
))
2394 /* Termcap_String_Ptr = Termcap_String_Buf; */
2395 # endif /* NOT USE_TERMCAP */
2397 Termcap_Initalized
= 1;
2399 Cls_Str
= SLtt_tgetstr ("cl");
2400 Curs_Pos_Str
= SLtt_tgetstr ("cm");
2402 if ((NULL
== (Ins_Mode_Str
= SLtt_tgetstr("im")))
2403 || ( NULL
== (Eins_Mode_Str
= SLtt_tgetstr("ei")))
2404 || ( NULL
== (Del_Char_Str
= SLtt_tgetstr("dc"))))
2405 SLtt_Term_Cannot_Insert
= 1;
2407 Visible_Bell_Str
= SLtt_tgetstr ("vb");
2408 Curs_Up_Str
= SLtt_tgetstr ("up");
2409 Rev_Scroll_Str
= SLtt_tgetstr("sr");
2410 Del_N_Lines_Str
= SLtt_tgetstr("DL");
2411 Add_N_Lines_Str
= SLtt_tgetstr("AL");
2413 /* Actually these are used to initialize terminals that use cursor
2414 * addressing. Hard to believe.
2416 Term_Init_Str
= SLtt_tgetstr ("ti");
2417 Term_Reset_Str
= SLtt_tgetstr ("te");
2419 /* If I do this for vtxxx terminals, arrow keys start sending ESC O A,
2420 * which I do not want. This is mainly for HP terminals.
2422 if ((almost_vtxxx
== 0) || SLtt_Force_Keypad_Init
)
2424 Keypad_Init_Str
= SLtt_tgetstr ("ks");
2425 Keypad_Reset_Str
= SLtt_tgetstr ("ke");
2428 /* Make up for defective termcap/terminfo databases */
2429 if ((Vt100_Like
&& (term
[2] != '1'))
2434 if (Del_N_Lines_Str
== NULL
) Del_N_Lines_Str
= "\033[%dM";
2435 if (Add_N_Lines_Str
== NULL
) Add_N_Lines_Str
= "\033[%dL";
2438 Scroll_R_Str
= SLtt_tgetstr("cs");
2440 SLtt_get_screen_size ();
2442 if ((Scroll_R_Str
== NULL
)
2443 || (((NULL
== Del_N_Lines_Str
) || (NULL
== Add_N_Lines_Str
))
2444 && (NULL
== Rev_Scroll_Str
)))
2450 /* Defective termcap mode!!!! */
2451 SLtt_set_term_vtxxx (NULL
);
2453 else SLtt_Term_Cannot_Scroll
= 1;
2456 Del_Eol_Str
= SLtt_tgetstr("ce");
2457 Del_Bol_Str
= SLtt_tgetstr("cb");
2458 if (is_xterm
&& (Del_Bol_Str
== NULL
))
2459 Del_Bol_Str
= "\033[1K";
2460 if (is_xterm
&& (Del_Eol_Str
== NULL
))
2461 Del_Eol_Str
= "\033[K";
2463 Rev_Vid_Str
= SLtt_tgetstr("mr");
2464 if (Rev_Vid_Str
== NULL
) Rev_Vid_Str
= SLtt_tgetstr("so");
2466 Bold_Vid_Str
= SLtt_tgetstr("md");
2468 /* Although xterm cannot blink, it does display the blinking characters
2469 * as bold ones. Some Rxvt will display the background as high intensity.
2471 if ((NULL
== (Blink_Vid_Str
= SLtt_tgetstr("mb")))
2473 Blink_Vid_Str
= "\033[5m";
2475 UnderLine_Vid_Str
= SLtt_tgetstr("us");
2477 Start_Alt_Chars_Str
= SLtt_tgetstr ("as"); /* smacs */
2478 End_Alt_Chars_Str
= SLtt_tgetstr ("ae"); /* rmacs */
2479 Enable_Alt_Char_Set
= SLtt_tgetstr ("eA"); /* enacs */
2480 SLtt_Graphics_Char_Pairs
= SLtt_tgetstr ("ac");
2482 if (NULL
== SLtt_Graphics_Char_Pairs
)
2484 /* make up for defective termcap/terminfo */
2487 Start_Alt_Chars_Str
= "\016";
2488 End_Alt_Chars_Str
= "\017";
2489 Enable_Alt_Char_Set
= "\033)0";
2493 /* aixterm added by willi */
2494 if (is_xterm
|| !strncmp (term
, "aixterm", 7))
2497 Start_Alt_Chars_Str
= "\016";
2498 End_Alt_Chars_Str
= "\017";
2499 Enable_Alt_Char_Set
= "\033(B\033)0";
2501 Start_Alt_Chars_Str
= "\033(0";
2502 End_Alt_Chars_Str
= "\033(B";
2503 Enable_Alt_Char_Set
= "";
2507 if ((SLtt_Graphics_Char_Pairs
== NULL
) &&
2508 ((Start_Alt_Chars_Str
== NULL
) || (End_Alt_Chars_Str
== NULL
)))
2510 SLtt_Has_Alt_Charset
= 0;
2511 Enable_Alt_Char_Set
= NULL
;
2513 else SLtt_Has_Alt_Charset
= 1;
2516 Enable_Alt_Char_Set
= Start_Alt_Chars_Str
= End_Alt_Chars_Str
= NULL
;
2519 /* status line capabilities */
2520 if ((SLtt_Has_Status_Line
== -1)
2521 && (0 != (SLtt_Has_Status_Line
= TGETFLAG ("hs"))))
2523 Disable_Status_line_Str
= SLtt_tgetstr ("ds");
2524 Return_From_Status_Line_Str
= SLtt_tgetstr ("fs");
2525 Goto_Status_Line_Str
= SLtt_tgetstr ("ts");
2526 /* Status_Line_Esc_Ok = TGETFLAG("es"); */
2527 Num_Status_Line_Columns
= SLtt_tgetnum ("ws");
2528 if (Num_Status_Line_Columns
< 0) Num_Status_Line_Columns
= 0;
2531 if (NULL
== (Norm_Vid_Str
= SLtt_tgetstr("me")))
2533 Norm_Vid_Str
= SLtt_tgetstr("se");
2536 Cursor_Invisible_Str
= SLtt_tgetstr("vi");
2537 Cursor_Visible_Str
= SLtt_tgetstr("ve");
2539 Curs_F_Str
= SLtt_tgetstr("RI");
2542 if (NULL
!= Curs_F_Str
)
2544 Len_Curs_F_Str
= strlen(Curs_F_Str
);
2546 else Len_Curs_F_Str
= strlen(Curs_Pos_Str
);
2549 Automatic_Margins
= TGETFLAG ("am");
2550 /* No_Move_In_Standout = !TGETFLAG ("ms"); */
2551 # ifdef HP_GLITCH_CODE
2552 Has_HP_Glitch
= TGETFLAG ("xs");
2554 Worthless_Highlight
= TGETFLAG ("xs");
2557 if (Worthless_Highlight
== 0)
2558 { /* Magic cookie glitch */
2559 Worthless_Highlight
= (SLtt_tgetnum ("sg") > 0);
2562 if (Worthless_Highlight
)
2563 SLtt_Has_Alt_Charset
= 0;
2565 Reset_Color_String
= SLtt_tgetstr ("op");
2567 /* Apparantly the difference between "AF" and "Sf" is that AF uses RGB,
2570 Color_Fg_Str
= SLtt_tgetstr ("AF"); /* ANSI setaf */
2571 if (Color_Fg_Str
== NULL
)
2573 Color_Fg_Str
= SLtt_tgetstr ("Sf"); /* setf */
2574 /* Is_Fg_BGR = (Color_Fg_Str != NULL); */
2576 Color_Bg_Str
= SLtt_tgetstr ("AB"); /* ANSI setbf */
2577 if (Color_Bg_Str
== NULL
)
2579 Color_Bg_Str
= SLtt_tgetstr ("Sb"); /* setb */
2580 /* Is_Fg_BGR = (Color_Bg_Str != NULL); */
2583 if ((Max_Terminfo_Colors
= SLtt_tgetnum ("Co")) < 0)
2584 Max_Terminfo_Colors
= 8;
2586 if ((Color_Bg_Str
!= NULL
) && (Color_Fg_Str
!= NULL
))
2587 SLtt_Use_Ansi_Colors
= 1;
2591 Color_Fg_Str
= "%?%p1%{7}%>%t\033[1;3%p1%{8}%m%dm%e\033[3%p1%dm%;";
2592 Color_Bg_Str
= "%?%p1%{7}%>%t\033[5;4%p1%{8}%m%dm%e\033[4%p1%dm%;";
2593 Max_Terminfo_Colors
= 16;
2595 Color_Fg_Str
= "\033[3%dm";
2596 Color_Bg_Str
= "\033[4%dm";
2597 Max_Terminfo_Colors
= 8;
2601 #if SLTT_HAS_NON_BCE_SUPPORT
2602 Can_Background_Color_Erase
= TGETFLAG ("ut"); /* bce */
2603 /* Modern xterms have the BCE capability as well as the linux console */
2604 if (Can_Background_Color_Erase
== 0)
2606 Can_Background_Color_Erase
= (Linux_Console
2607 # if SLTT_XTERM_ALWAYS_BCE
2616 if ((Cls_Str
== NULL
)
2617 || (Curs_Pos_Str
== NULL
))
2626 /* specific to vtxxx only */
2627 void SLtt_enable_cursor_keys (void)
2632 tt_write_string("\033=\033[?1l");
2636 int SLtt_initialize (char *term
)
2638 SLtt_get_terminfo ();
2642 void SLtt_get_terminfo ()
2646 /* Apparantly, this cannot fail according to the man pages. */
2647 if (SLang_TT_Write_FD
== -1)
2648 SLang_TT_Write_FD
= fileno (stdout
);
2650 Can_Background_Color_Erase
= 0;
2652 Color_Fg_Str
= "\033[3%dm";
2653 Color_Bg_Str
= "\033[4%dm";
2654 Max_Terminfo_Colors
= 8;
2658 SLtt_set_term_vtxxx(&zero
);
2659 Start_Alt_Chars_Str
= "\016";
2660 End_Alt_Chars_Str
= "\017";
2661 SLtt_Has_Alt_Charset
= 1;
2662 SLtt_Graphics_Char_Pairs
= "aaffgghhjjkkllmmnnooqqssttuuvvwwxx";
2663 Enable_Alt_Char_Set
= "\033(B\033)0";
2664 SLtt_get_screen_size ();
2668 /* This sets term for vt102 terminals it parameter vt100 is 0. If vt100
2669 * is non-zero, set terminal appropriate for a only vt100
2670 * (no add line capability). */
2672 void SLtt_set_term_vtxxx(int *vt100
)
2674 Norm_Vid_Str
= "\033[m";
2676 Scroll_R_Str
= "\033[%i%d;%dr";
2677 Cls_Str
= "\033[2J\033[H";
2678 Rev_Vid_Str
= "\033[7m";
2679 Bold_Vid_Str
= "\033[1m";
2680 Blink_Vid_Str
= "\033[5m";
2681 UnderLine_Vid_Str
= "\033[4m";
2682 Del_Eol_Str
= "\033[K";
2683 Del_Bol_Str
= "\033[1K";
2684 Rev_Scroll_Str
= "\033M";
2685 Curs_F_Str
= "\033[%dC";
2686 /* Len_Curs_F_Str = 5; */
2687 Curs_Pos_Str
= "\033[%i%d;%dH";
2688 if ((vt100
== NULL
) || (*vt100
== 0))
2690 Ins_Mode_Str
= "\033[4h";
2691 Eins_Mode_Str
= "\033[4l";
2692 Del_Char_Str
= "\033[P";
2693 Del_N_Lines_Str
= "\033[%dM";
2694 Add_N_Lines_Str
= "\033[%dL";
2695 SLtt_Term_Cannot_Insert
= 0;
2699 Del_N_Lines_Str
= NULL
;
2700 Add_N_Lines_Str
= NULL
;
2701 SLtt_Term_Cannot_Insert
= 1;
2703 SLtt_Term_Cannot_Scroll
= 0;
2704 /* No_Move_In_Standout = 0; */
2707 int SLtt_init_video (void)
2709 /* send_string_to_term("\033[?6h"); */
2710 /* relative origin mode */
2711 tt_write_string (Term_Init_Str
);
2712 tt_write_string (Keypad_Init_Str
);
2713 SLtt_reset_scroll_region();
2715 tt_write_string (Enable_Alt_Char_Set
);
2716 Video_Initialized
= 1;
2720 int SLtt_reset_video (void)
2722 SLtt_goto_rc (SLtt_Screen_Rows
- 1, 0);
2724 SLtt_normal_video (); /* MSKermit requires this */
2725 tt_write_string(Norm_Vid_Str
);
2727 Current_Fgbg
= 0xFFFFFFFFU
;
2728 SLtt_set_alt_char_set (0);
2729 if (SLtt_Use_Ansi_Colors
)
2731 if (Reset_Color_String
== NULL
)
2733 SLtt_Char_Type attr
;
2734 if (-1 != make_color_fgbg (NULL
, NULL
, &attr
))
2735 write_attributes (attr
);
2736 else tt_write_string ("\033[0m\033[m");
2738 else tt_write_string (Reset_Color_String
);
2739 Current_Fgbg
= 0xFFFFFFFFU
;
2742 tt_write_string (Keypad_Reset_Str
);
2743 tt_write_string (Term_Reset_Str
);
2745 if (Mouse_Mode
== 1)
2746 SLtt_set_mouse_mode (0, 1);
2748 SLtt_flush_output ();
2749 Video_Initialized
= 0;
2753 void SLtt_bold_video (void)
2755 tt_write_string (Bold_Vid_Str
);
2758 int SLtt_set_mouse_mode (int mode
, int force
)
2764 if (NULL
== (term
= (char *) getenv("TERM"))) return -1;
2765 if (strncmp ("xterm", term
, 5))
2769 Mouse_Mode
= (mode
!= 0);
2772 tt_write_string ("\033[?9h");
2774 tt_write_string ("\033[?9l");
2779 void SLtt_disable_status_line (void)
2781 if (SLtt_Has_Status_Line
> 0)
2783 tt_write_string (Disable_Status_line_Str
);
2784 SLtt_flush_output ();
2788 int SLtt_write_to_status_line (char *s
, int col
)
2790 if ((SLtt_Has_Status_Line
<= 0)
2791 || (Goto_Status_Line_Str
== NULL
)
2792 || (Return_From_Status_Line_Str
== NULL
))
2795 tt_printf (Goto_Status_Line_Str
, col
, 0);
2796 tt_write_string (s
);
2797 tt_write_string (Return_From_Status_Line_Str
);
2801 void SLtt_get_screen_size (void)
2805 unsigned short chan
;
2806 $
DESCRIPTOR(dev_dsc
, "SYS$INPUT:");
2811 struct winsize wind_struct
;
2815 if ((ioctl(1,TIOCGWINSZ
,&wind_struct
) == 0)
2816 || (ioctl(0, TIOCGWINSZ
, &wind_struct
) == 0)
2817 || (ioctl(2, TIOCGWINSZ
, &wind_struct
) == 0))
2819 c
= (int) wind_struct
.ws_col
;
2820 r
= (int) wind_struct
.ws_row
;
2824 while (errno
== EINTR
);
2829 status
= sys$
assign(&dev_dsc
,&chan
,0,0,0);
2832 code
= DVI$_DEVBUFSIZ
;
2833 status
= lib$
getdvi(&code
, &chan
,0, &c
, 0,0);
2836 code
= DVI$_TT_PAGE
;
2837 status
= lib$
getdvi(&code
, &chan
,0, &r
, 0,0);
2846 char *s
= getenv ("LINES");
2847 if (s
!= NULL
) r
= atoi (s
);
2852 char *s
= getenv ("COLUMNS");
2853 if (s
!= NULL
) c
= atoi (s
);
2856 if ((r
<= 0) || (r
> SLTT_MAX_SCREEN_ROWS
)) r
= 24;
2857 if ((c
<= 0) || (c
> SLTT_MAX_SCREEN_COLS
)) c
= 80;
2858 SLtt_Screen_Rows
= r
;
2859 SLtt_Screen_Cols
= c
;
2862 #if SLTT_HAS_NON_BCE_SUPPORT
2863 int _pSLtt_get_bce_color_offset (void)
2865 if ((SLtt_Use_Ansi_Colors
== 0)
2866 || Can_Background_Color_Erase
2867 || SLtt_Use_Blink_For_ACS
) /* in this case, we cannot lose a color */
2868 Bce_Color_Offset
= 0;
2871 SLtt_Char_Type fgbg
= get_brush_fgbg (0);
2872 if (GET_BG(fgbg
) == SLSMG_COLOR_DEFAULT
)
2873 Bce_Color_Offset
= 0;
2875 Bce_Color_Offset
= 1;
2878 return Bce_Color_Offset
;
2882 int SLtt_utf8_enable (int mode
)
2885 mode
= _pSLutf8_mode
;
2887 return _pSLtt_UTF8_Mode
= mode
;
2890 int SLtt_is_utf8_mode (void)
2892 int mode
= _pSLtt_UTF8_Mode
;
2894 mode
= _pSLutf8_mode
;