Add $ and ` for escaping and reorder it according to the ascii values
[midnight-commander.git] / slang / sldisply.c
blob909ef87396185dc38e7e56622d9fa8fa5d27a967
1 /*
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,
19 USA.
22 #include "slinclud.h"
24 #include <time.h>
25 #include <ctype.h>
27 #if !defined(VMS) || (__VMS_VER >= 70000000)
28 # include <sys/time.h>
29 # ifdef __QNX__
30 # include <sys/select.h>
31 # endif
32 # include <sys/types.h>
33 #endif
35 #ifdef __BEOS__
36 /* Prototype for select */
37 # include <net/socket.h>
38 #endif
40 #ifdef HAVE_TERMIOS_H
41 # include <termios.h>
42 #endif
44 #ifdef VMS
45 # include <unixlib.h>
46 # include <unixio.h>
47 # include <dvidef.h>
48 # include <descrip.h>
49 # include <lib$routines.h>
50 # include <starlet.h>
51 #else
52 # if !defined(sun)
53 # include <sys/ioctl.h>
54 # endif
55 #endif
57 #ifdef SYSV
58 # include <sys/termio.h>
59 # include <sys/stream.h>
60 # include <sys/ptem.h>
61 # include <sys/tty.h>
62 #endif
64 #if defined (_AIX) && !defined (FD_SET)
65 # include <sys/select.h> /* for FD_ISSET, FD_SET, FD_ZERO */
66 #endif
68 #include <errno.h>
70 #if defined(__DECC) && defined(VMS)
71 /* These get prototypes for write an sleep */
72 # include <unixio.h>
73 #endif
74 #include <signal.h>
76 #include "slang.h"
77 #include "_slang.h"
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
82 * structure below. */
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;
115 #endif
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;
131 #endif
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.
142 * -------
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
152 typedef struct
154 SLtt_Char_Type fgbg;
155 SLtt_Char_Type mono;
157 Brush_Info_Type;
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 */
202 #if 0
203 static char *Start_Mouse_Rpt_Str; /* Start mouse reporting mode */
204 static char *End_Mouse_Rpt_Str; /* End mouse reporting mode */
205 #endif
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)
249 struct timeval tv;
250 tv.tv_sec = usecs / 1000000;
251 tv.tv_usec = usecs % 1000000;
252 return select(0, NULL, NULL, NULL, &tv);
253 #else
254 return 0;
255 #endif
258 int SLtt_flush_output (void)
260 int nwrite = 0;
261 unsigned int total;
262 int n = (int) (Output_Bufferp - Output_Buffer);
264 SLtt_Num_Chars_Output += n;
266 total = 0;
267 while (n > 0)
269 nwrite = write (SLang_TT_Write_FD, (char *) Output_Buffer + total, n);
270 if (nwrite == -1)
272 nwrite = 0;
273 #ifdef EAGAIN
274 if (errno == EAGAIN)
276 _pSLusleep (100000); /* 1/10 sec */
277 continue;
279 #endif
280 #ifdef EWOULDBLOCK
281 if (errno == EWOULDBLOCK)
283 _pSLusleep (100000);
284 continue;
286 #endif
287 #ifdef EINTR
288 if (errno == EINTR) continue;
289 #endif
290 break;
292 n -= nwrite;
293 total += nwrite;
295 Output_Bufferp = Output_Buffer;
296 return n;
299 int SLtt_Baud_Rate;
300 static void tt_write(char *str, unsigned int n)
302 static unsigned long last_time;
303 static int total;
304 unsigned long now;
305 unsigned int ndiff;
307 if ((str == NULL) || (n == 0)) return;
308 total += n;
310 while (1)
312 ndiff = MAX_OUTPUT_BUFFER_SIZE - (int) (Output_Bufferp - Output_Buffer);
313 if (ndiff < n)
315 SLMEMCPY ((char *) Output_Bufferp, str, ndiff);
316 Output_Bufferp += ndiff;
317 SLtt_flush_output ();
318 n -= ndiff;
319 str += ndiff;
321 else
323 SLMEMCPY ((char *) Output_Bufferp, str, n);
324 Output_Bufferp += n;
325 break;
329 if (((SLtt_Baud_Rate > 150) && (SLtt_Baud_Rate <= 9600))
330 && (10 * total > SLtt_Baud_Rate))
332 total = 0;
333 if ((now = (unsigned long) time(NULL)) - last_time <= 1)
335 SLtt_flush_output ();
336 sleep((unsigned) 1);
338 last_time = now;
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);
350 Cursor_Set = 0;
353 void SLtt_putchar (char ch)
355 SLtt_normal_video ();
356 if (Cursor_Set == 1)
358 if (ch >= ' ') Cursor_c++;
359 else if (ch == '\b') Cursor_c--;
360 else if (ch == '\r') Cursor_c = 0;
361 else Cursor_Set = 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)
376 char *fmt_max;
377 unsigned char *b, *bmax, ch;
378 int offset;
379 int z, z1, parse_level;
380 int zero_pad;
381 int field_width;
382 int variables [26];
383 int stack [64];
384 unsigned int stack_len;
385 int parms [10];
386 #define STACK_POP (stack_len ? stack[--stack_len] : 0)
388 if (fmt == NULL)
390 *buf = 0;
391 return 0;
394 stack [0] = y; /* pushed for termcap */
395 stack [1] = x;
396 stack_len = 2;
398 parms [1] = x; /* p1 */
399 parms [2] = y; /* p2 */
401 offset = 0;
402 zero_pad = 0;
403 field_width = 0;
405 b = (unsigned char *) buf;
406 bmax = b + buflen;
408 fmt_max = fmt + strlen (fmt);
410 while ((fmt < fmt_max) && (b < bmax))
412 ch = *fmt++;
414 if (ch != '%')
416 *b++ = ch;
417 continue;
420 if (fmt == fmt_max) break;
421 ch = *fmt++;
423 switch (ch)
425 default:
426 *b++ = ch;
427 break;
429 case 'p':
431 if (fmt == fmt_max) break;
432 ch = *fmt++;
433 if ((ch >= '0') && (ch <= '9'))
434 stack [stack_len++] = parms [ch - '0'];
435 break;
437 case '\'': /* 'x' */
438 if (fmt == fmt_max) break;
439 stack [stack_len++] = *fmt++;
440 if (fmt < fmt_max) fmt++; /* skip ' */
441 break;
443 case '{': /* literal constant, e.g. {30} */
444 z = 0;
445 while ((fmt < fmt_max) && ((ch = *fmt) <= '9') && (ch >= '0'))
447 z = z * 10 + (ch - '0');
448 fmt++;
450 stack [stack_len++] = z;
451 if ((ch == '}') && (fmt < fmt_max)) fmt++;
452 break;
454 case '0':
455 if (fmt == fmt_max) break;
456 ch = *fmt;
457 if ((ch != '2') && (ch != '3'))
458 break;
459 zero_pad = 1;
460 fmt++;
461 /* drop */
463 case '2':
464 case '3':
465 if (fmt == fmt_max) break;
466 if (*fmt == 'x')
468 char x_fmt_buf [4];
469 char *x_fmt_buf_ptr;
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';
475 *x_fmt_buf_ptr = 0;
477 z = STACK_POP;
478 z += offset;
480 sprintf ((char *)b, x_fmt_buf, z);
481 b += strlen ((char *)b);
482 zero_pad = 0;
483 break;
486 field_width = (ch - '0');
487 /* drop */
489 case 'd':
490 z = STACK_POP;
491 z += offset;
492 if (z >= 100)
494 *b++ = z / 100 + '0';
495 z = z % 100;
496 zero_pad = 1;
497 field_width = 2;
499 else if (zero_pad && (field_width == 3))
500 *b++ = '0';
502 if (b == bmax) break;
503 if (z >= 10)
505 *b++ = z / 10 + '0';
506 z = z % 10;
508 else if (zero_pad && (field_width >= 2))
509 *b++ = '0';
511 if (b == bmax) break;
512 *b++ = z + '0';
513 field_width = zero_pad = 0;
514 break;
516 case 'x':
517 z = STACK_POP;
518 z += offset;
519 if (b + 16 >= bmax)
520 break;
521 sprintf ((char *) b, "%X", z);
522 b += strlen ((char *)b);
523 break;
525 case 'i':
526 offset = 1;
527 break;
529 case '+':
530 /* Handling this depends upon whether or not we are parsing
531 * terminfo. Terminfo requires the stack so use it as an
532 * indicator.
534 if (stack_len > 2)
536 z = STACK_POP;
537 stack [stack_len - 1] += z;
539 else if (fmt < fmt_max)
541 ch = *fmt++;
542 if ((unsigned char) ch == 128) ch = 0;
543 ch = ch + (unsigned char) STACK_POP;
544 if (ch == '\n') ch++;
545 *b++ = ch;
547 break;
549 /* Binary operators */
550 case '-':
551 case '*':
552 case '/':
553 case 'm':
554 case '&':
555 case '|':
556 case '^':
557 case '=':
558 case '>':
559 case '<':
560 case 'A':
561 case 'O':
562 z1 = STACK_POP;
563 z = STACK_POP;
564 switch (ch)
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;
580 break;
582 /* unary */
583 case '!':
584 z = STACK_POP;
585 stack [stack_len++] = !z;
586 break;
588 case '~':
589 z = STACK_POP;
590 stack [stack_len++] = ~z;
591 break;
593 case 'r': /* termcap -- swap parameters */
594 z = stack [0];
595 stack [0] = stack [1];
596 stack [1] = z;
597 break;
599 case '.': /* termcap */
600 case 'c':
601 ch = (unsigned char) STACK_POP;
602 if (ch == '\n') ch++;
603 *b++ = ch;
604 break;
606 case 'g':
607 if (fmt == fmt_max) break;
608 ch = *fmt++;
609 if ((ch >= 'a') && (ch <= 'z'))
610 stack [stack_len++] = variables [ch - 'a'];
611 break;
613 case 'P':
614 if (fmt == fmt_max) break;
615 ch = *fmt++;
616 if ((ch >= 'a') && (ch <= 'z'))
617 variables [ch - 'a'] = STACK_POP;
618 break;
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
624 * endif.
626 case '?': /* if */
627 case ';': /* endif */
628 break;
630 case 't': /* then */
631 z = STACK_POP;
632 if (z != 0)
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.
638 /* drop */
639 case 'e': /* else */
641 parse_level = 0;
642 while (fmt < fmt_max)
644 unsigned char ch1;
646 ch1 = *fmt++;
647 if ((ch1 != '%') || (fmt == fmt_max))
648 continue;
650 ch1 = *fmt++;
652 if (ch1 == '?') parse_level++; /* new if */
653 else if (ch1 == 'e')
655 if ((ch != 'e') && (parse_level == 0))
656 break;
658 else if (ch1 == ';')
660 if (parse_level == 0)
661 break;
662 parse_level--;
665 break;
668 if (b >= bmax)
669 b = bmax - 1;
670 *b = 0;
672 return (unsigned int) (b - (unsigned char *) buf);
675 static void tt_printf(char *fmt, int x, int y)
677 char buf[1024];
678 unsigned int n;
679 if (fmt == NULL) return;
680 n = tt_sprintf(buf, sizeof (buf), fmt, x, y);
681 tt_write(buf, n);
684 void SLtt_set_scroll_region (int r1, int r2)
686 Scroll_r1 = r1;
687 Scroll_r2 = r2;
688 tt_printf (Scroll_R_Str, Scroll_r1, Scroll_r2);
689 Cursor_Set = 0;
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))
700 return -1;
702 tt_write_string (show ? Cursor_Visible_Str : Cursor_Invisible_Str);
703 return 0;
706 /* the goto_rc function moves to row relative to scrolling region */
707 void SLtt_goto_rc(int r, int c)
709 char *s = NULL;
710 int n;
711 char buf[6];
713 if ((c < 0) || (r < 0))
715 Cursor_Set = 0;
716 return;
719 /* if (No_Move_In_Standout && Current_Fgbg) SLtt_normal_video (); */
720 r += Scroll_r1;
722 if ((Cursor_Set > 0) || ((Cursor_Set < 0) && !Automatic_Margins))
724 n = r - Cursor_r;
725 if ((n == -1) && (Cursor_Set > 0) && (Cursor_c == c)
726 && (Curs_Up_Str != NULL))
728 s = Curs_Up_Str;
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. */
741 if (!QANSI_Console)
743 s = buf;
744 *s++ = '\b'; *s = 0;
745 s = buf;
747 else
749 /* do the generic cursor positioning,
750 without an optimization */
751 s = NULL;
755 else if ((c == 0) && (!QANSI_Console)) /* the same things
756 for the qansi-m console limitation */
758 s = buf;
759 if ((Cursor_Set != 1) || (Cursor_c != 0)) *s++ = '\r';
760 while (n--) *s++ = '\n';
761 #ifdef VMS
762 /* Need to add this after \n to start a new record. Sheesh. */
763 *s++ = '\r';
764 #endif
765 *s = 0;
766 s = buf;
768 /* Will fail on VMS */
769 #ifndef VMS
770 else if ((SLtt_Newline_Ok && (Cursor_Set == 1) &&
771 (Cursor_c >= c) && (c + 3 > Cursor_c)) &&
772 (!QANSI_Console))
774 s = buf;
775 while (n--) *s++ = '\n';
776 n = Cursor_c - c;
777 while (n--) *s++ = '\b';
778 *s = 0;
779 s = buf;
781 #endif
784 if (s != NULL) tt_write_string(s);
785 else tt_printf(Curs_Pos_Str, r, c);
786 Cursor_c = c; Cursor_r = r;
787 Cursor_Set = 1;
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)
808 tt_write ("\r", 1);
809 Cursor_Set = 1; Cursor_c = 0;
810 SLtt_del_eol();
811 /* Put the cursor back at the beginning of the line */
812 tt_write ("\r", 1);
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);
823 SLtt_del_eol ();
826 void SLtt_delete_nlines (int nn)
828 int r1, curs;
829 unsigned int n;
831 if (nn <= 0) return;
832 n = (unsigned int) nn;
834 SLtt_normal_video ();
836 if (Scroll_r1 == Scroll_r2)
838 delete_line_in_scroll_region ();
839 return;
842 if (Del_N_Lines_Str != NULL) tt_printf(Del_N_Lines_Str, n, 0);
843 else
844 /* get a new terminal */
846 char buf[80];
847 unsigned int dn = n;
849 if (dn > sizeof (buf))
850 dn = sizeof (buf);
852 SLMEMSET (buf, '\n', dn);
853 while (n > dn)
855 tt_write (buf, dn);
856 n -= dn;
858 tt_write (buf, n);
860 r1 = Scroll_r1;
861 curs = Cursor_r;
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);
872 void SLtt_cls (void)
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
876 * necessary.
878 if ((SLtt_Use_Ansi_Colors == 0) && Is_Color_Terminal)
880 if (Reset_Color_String != NULL)
881 tt_write_string (Reset_Color_String);
882 else
883 tt_write ("\033[0m\033[m", 7);
886 SLtt_normal_video();
887 SLtt_reset_scroll_region ();
888 tt_write_string(Cls_Str);
891 void SLtt_reverse_index (int n)
893 if (!n) return;
895 SLtt_normal_video();
897 if (Scroll_r1 == Scroll_r2)
899 delete_line_in_scroll_region ();
900 return;
903 if (Add_N_Lines_Str != NULL) tt_printf(Add_N_Lines_Str,n, 0);
904 else
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);
920 #ifdef __linux__
921 else if (Linux_Console)
923 tt_write ("\033[?5h", 5);
924 SLtt_flush_output ();
925 _pSLusleep (50000);
926 tt_write ("\033[?5l", 5);
928 #endif
930 SLtt_flush_output ();
933 static void write_string_with_care (char *);
935 static void del_eol (void)
937 #if 0
938 int c;
939 #endif
940 if ((Del_Eol_Str != NULL)
941 && (Can_Background_Color_Erase || ((Current_Fgbg & ~0xFF) == 0)))
943 tt_write_string(Del_Eol_Str);
944 return;
947 #if 0
948 c = Cursor_c;
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)
955 c++;
957 while (c < SLtt_Screen_Cols)
959 tt_write (" ", 1);
960 c++;
962 Cursor_c = (SLtt_Screen_Cols-1);
963 #else
964 while (Cursor_c < SLtt_Screen_Cols)
966 write_string_with_care (" ");
967 Cursor_c++;
969 Cursor_c = SLtt_Screen_Cols - 1;
970 Cursor_Set = 0;
971 #endif
974 void SLtt_del_eol (void)
976 if (Current_Fgbg != 0xFFFFFFFFU) SLtt_normal_video ();
977 del_eol ();
980 typedef SLCONST struct
982 char *name;
983 SLtt_Char_Type color;
985 Color_Def_Type;
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)
1014 int fg, bg;
1015 Brush_Info_Type *b, *bmax;
1017 b = Brush_Table;
1018 bmax = b + JMAX_COLORS;
1020 bg = 0;
1021 while (b < bmax)
1023 fg = 7;
1024 while (b < bmax)
1026 if (fg != bg)
1028 b->fgbg = MAKE_COLOR(fg,bg);
1029 b->mono = SLTT_REV_MASK;
1030 b++;
1032 if (fg == 0)
1033 break;
1034 fg--;
1036 bg++;
1037 if (bg == 8)
1038 bg = 0;
1041 Brush_Table[0].mono = 0;
1042 Brushes_Initialized = 1;
1043 return 0;
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)
1055 color = 0;
1057 return Brush_Table + color;
1060 static SLtt_Char_Type get_brush_attr (unsigned int color)
1062 Brush_Info_Type *b;
1064 if (NULL == (b = get_brush_info (color)))
1065 return (SLtt_Char_Type)-1;
1067 if (SLtt_Use_Ansi_Colors)
1068 return b->fgbg;
1070 return b->mono;
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)
1080 Brush_Info_Type *b;
1082 (void) what;
1083 if (NULL == (b = get_brush_info (obj)))
1084 return -1;
1086 b->mono = mask & ATTR_MASK;
1087 return 0;
1090 static char *check_color_for_digit_form (char *color)
1092 unsigned int i, ich;
1093 unsigned char *s = (unsigned char *) color;
1095 i = 0;
1096 while ((ich = (unsigned int) *s) != 0)
1098 if ((ich < '0') || (ich > '9'))
1099 return color;
1101 i = i * 10 + (ich - '0');
1102 s++;
1105 if (i < MAX_COLOR_NAMES)
1106 color = Color_Defs[i].name;
1108 return color;
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;
1115 char *p, *pmax;
1117 if (already_parsed == -1)
1118 return -1;
1120 if (already_parsed)
1122 *fgp = fg;
1123 *bgp = bg;
1124 return 0;
1127 already_parsed = -1;
1129 bg = getenv ("COLORFGBG");
1131 if (bg == NULL)
1133 bg = getenv ("DEFAULT_COLORS");
1134 if (bg == NULL)
1135 return -1;
1138 p = fg_buf;
1139 pmax = p + (sizeof (fg_buf) - 1);
1141 while ((*bg != 0) && (*bg != ';'))
1143 if (p < pmax) *p++ = *bg;
1144 bg++;
1146 *p = 0;
1148 if (*bg) bg++;
1150 p = bg_buf;
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;
1159 bg++;
1161 *p = 0;
1163 if (!strcmp (fg_buf, "default") || !strcmp(bg_buf, "default"))
1165 *fgp = *bgp = fg = bg = "default";
1167 else
1169 *fgp = fg = check_color_for_digit_form (fg_buf);
1170 *bgp = bg = check_color_for_digit_form (bg_buf);
1172 already_parsed = 1;
1173 return 0;
1176 static int Color_0_Modified = 0;
1178 int SLtt_set_color_object (int obj, SLtt_Char_Type attr)
1180 Brush_Info_Type *b;
1182 if (NULL == (b = get_brush_info (obj)))
1183 return -1;
1185 b->fgbg = attr;
1186 if (obj == 0) Color_0_Modified = 1;
1188 if (_pSLtt_color_changed_hook != NULL)
1189 (*_pSLtt_color_changed_hook)();
1191 return 0;
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)
1201 Brush_Info_Type *b;
1203 if (NULL == (b = get_brush_info (obj)))
1204 return -1;
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)();
1212 return 0;
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.
1230 attr = 0;
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;
1236 f &= 0x7;
1239 if (b != SLSMG_COLOR_DEFAULT)
1241 if (b & 0x8) attr |= SLTT_BLINK_MASK;
1242 b &= 0x7;
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)
1253 unsigned int i;
1254 unsigned char ch;
1256 if (strncmp (color, "color", 5))
1257 return -1;
1259 color += 5;
1260 if (*color == 0)
1261 return -1;
1263 i = 0;
1264 while (1)
1266 unsigned int j;
1268 ch = (unsigned char) *color++;
1269 if (ch == 0)
1270 break;
1271 if ((ch > '9') || (ch < '0'))
1272 return -1;
1274 if (i > 0xFFFFFFFFU / 10)
1275 return -1;
1276 j = (i *= 10);
1277 i += (ch - '0');
1278 if (i < j)
1279 return -1;
1282 *f = (SLtt_Char_Type) i;
1283 return 0;
1286 static int make_color_fgbg (char *fg, char *bg, SLtt_Char_Type *fgbg)
1288 SLtt_Char_Type f = 0xFFFFFFFFU, b = 0xFFFFFFFFU;
1289 char *dfg, *dbg;
1290 unsigned int i;
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))
1298 return -1;
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;
1310 break;
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;
1320 break;
1324 if ((f == 0xFFFFFFFFU) || (b == 0xFFFFFFFFU))
1325 return -1;
1327 *fgbg = fb_to_fgbg (f, b);
1328 return 0;
1331 int SLtt_set_color (int obj, char *what, char *fg, char *bg)
1333 SLtt_Char_Type fgbg;
1335 (void) what;
1337 if (-1 == make_color_fgbg (fg, bg, &fgbg))
1338 return -1;
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)
1350 static int last_i;
1351 if (SLtt_Has_Alt_Charset == 0) return;
1353 i = (i != 0);
1355 if (i == last_i) return;
1356 tt_write_string (i ? Start_Alt_Chars_Str : End_Alt_Chars_Str );
1357 last_i = i;
1360 static void write_attributes (SLtt_Char_Type fgbg)
1362 int bg0, fg0;
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);
1411 else
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);
1420 else
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;
1444 return;
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;
1476 ca = COLOR_OF(a);
1477 cb = COLOR_OF(b);
1479 if (ca == cb)
1480 return 1;
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))
1494 return 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)
1504 unsigned int len;
1506 if (str == NULL) return;
1508 len = strlen (str);
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;
1520 else
1521 len = 0;
1524 else
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)
1531 char *p;
1532 nchars = SLtt_Screen_Cols - Cursor_c - 1;
1533 p = (char *)SLutf8_skip_chars((SLuchar_Type *) str, (SLuchar_Type *)(str + len), nchars, NULL, 1);
1534 len = p - str;
1536 else
1537 len = 0;
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;
1550 int dcursor_c;
1552 p = out;
1553 pmax = p + (sizeof (out)-1);
1555 dcursor_c = 0;
1556 while (s < smax)
1558 SLwchar_Type wch;
1559 unsigned int nchars;
1561 if (0 == (nchars = s->nchars))
1563 /* 2nd element of a char that occupies two columns */
1564 s++;
1565 if (_pSLtt_UTF8_Mode == 0)
1566 *p++ = ' ';
1567 dcursor_c++;
1568 continue;
1571 color = s->color;
1573 #if SLTT_HAS_NON_BCE_SUPPORT
1574 if (Bce_Color_Offset
1575 && (color >= Bce_Color_Offset))
1576 color -= Bce_Color_Offset;
1577 #endif
1579 wch = s->wchars[0];
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)
1596 if ((wch != ' ')
1597 || (nchars > 1)
1598 /* it is a space so only consider it different if it
1599 * has different attributes.
1601 || (attr != Current_Fgbg)
1604 if (p != out)
1606 *p = 0;
1607 write_string_with_care ((char *) out);
1608 p = out;
1609 Cursor_c += dcursor_c;
1610 dcursor_c = 0;
1612 write_attributes (attr);
1613 last_color = color;
1618 if ((wch < 0x80) && (nchars == 1))
1619 *p++ = (unsigned char) wch;
1620 else if (_pSLtt_UTF8_Mode == 0)
1622 if (wch > 255)
1623 wch = '?';
1624 else if (wch < (SLwchar_Type)SLsmg_Display_Eight_Bit)
1625 wch = '?';
1626 *p++ = (unsigned char) wch;
1628 else
1630 unsigned int i;
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");
1636 return;
1640 dcursor_c++;
1641 s++;
1643 *p = 0;
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)
1650 char buf [1024];
1653 /* if (Current_Fgbg & ~0xFF) */
1654 /* { */
1655 /* unsigned int num = 0; */
1656 /* while (num < n) */
1657 /* { */
1658 /* write_string_with_care (" "); */
1659 /* num++; */
1660 /* } */
1661 /* Cursor_c += n; */
1662 /* return; */
1663 /* } */
1666 if (n <= 4)
1668 SLtt_normal_video ();
1669 #if 0
1670 if (n >= sizeof (buf))
1671 n = sizeof (buf) - 1;
1672 #endif
1673 SLMEMSET (buf, ' ', n);
1674 buf[n] = 0;
1675 write_string_with_care (buf);
1676 Cursor_c += n;
1678 else if (Curs_F_Str != NULL)
1680 Cursor_c += n;
1681 n = tt_sprintf(buf, sizeof (buf), Curs_F_Str, (int) n, 0);
1682 tt_write(buf, n);
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;
1713 #endif
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)
1724 && (len > 1)
1725 && (SLtt_Term_Cannot_Insert == 0)
1726 && Automatic_Margins)
1728 SLsmg_Char_Type *a, *b;
1729 insert_hack_char = &neww[len-1];
1731 a = oldd+(len-1);
1732 b = neww+(len-1);
1734 if (CHAR_EQS(a,b))
1735 insert_hack_char = NULL;
1736 else
1737 insert_hack_prev = &neww[len-2];
1739 #endif
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;
1749 q = oldd; p = neww;
1750 qmax = oldd + len;
1751 pmax = p + len;
1753 /* Find out where to begin --- while they match, we are ok */
1754 while (1)
1756 if (q == qmax) return;
1758 #if SLANG_HAS_KANJI_SUPPORT
1759 if (*p & 0x80)
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 */
1767 else
1768 { /* kanji match ! */
1769 if (!COLOR_EQS(*q, *p)) break;
1770 q++; p++;
1771 if (!COLOR_EQS(*q, *p)) break;
1772 /* really match! */
1773 q++; p++;
1774 continue;
1777 else break; /* old is not kanji */
1779 else
1780 { /* new is not kanji */
1781 if (*q & 0x80) break; /* old is kanji */
1783 #endif
1784 if (!CHAR_EQS(q, p)) break;
1785 q++; p++;
1788 #ifdef HP_GLITCH_CODE
1789 if (Has_HP_Glitch)
1791 SLsmg_Char_Type *qq = q;
1793 SLtt_goto_rc (row, (int) (p - neww));
1795 while (qq < qmax)
1797 if (qq->color)
1799 SLtt_normal_video ();
1800 SLtt_del_eol ();
1801 qmax = q;
1802 handle_hp_glitch = 1;
1803 break;
1805 qq++;
1808 #endif
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;
1824 while (pmax > p)
1826 pmax--;
1827 if (!CHAR_EQS(pmax, space_char))
1829 pmax++;
1830 break;
1835 while (qmax > q)
1837 qmax--;
1838 if (!CHAR_EQS(qmax, space_char))
1840 qmax++;
1841 break;
1845 last_buffered_match = buf = buffer; /* buffer is empty */
1847 #ifdef HP_GLITCH_CODE
1848 if (handle_hp_glitch)
1850 while (p < pmax)
1852 *buf++ = *p++;
1855 #endif
1857 #ifdef HP_GLITCH_CODE
1858 if (Has_HP_Glitch == 0)
1860 #endif
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;
1867 p1 = neww;
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)))
1874 p1++;
1876 else
1878 /* black+white attributes do not support bce */
1879 while ((p1 < pmax) && (CHAR_EQS_SPACE (p1)))
1880 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)
1888 && (p1 >= p)
1889 /* Avoid erasing from the end of the line */
1890 && ((p1 != pmax) || (pmax < neww + len)))
1892 int ofs = (int) (p1 - neww);
1893 q = oldd + ofs;
1894 p = p1;
1895 SLtt_goto_rc (row, ofs - 1);
1896 SLtt_reverse_video (blank_color);
1897 tt_write_string (Del_Bol_Str);
1898 tt_write (" ", 1);
1899 Cursor_c += 1;
1901 else
1902 SLtt_goto_rc (row, (int) (p - neww));
1904 else
1905 SLtt_goto_rc (row, (int) (p - neww));
1906 #ifdef HP_GLITCH_CODE
1908 #endif
1911 /* loop using overwrite then skip algorithm until done */
1912 while (1)
1914 /* while they do not match and we do not hit a space, buffer them up */
1915 n_spaces = 0;
1916 while (p < pmax)
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.
1924 space_match = p;
1925 p++; q++;
1926 while ((p < pmax)
1927 && CHAR_EQS_SPACE(q)
1928 && CHAR_EQS_SPACE(p))
1930 p++;
1931 q++;
1933 n_spaces = (unsigned int) (p - space_match);
1934 break;
1936 #if SLANG_HAS_KANJI_SUPPORT
1937 if ((*p & 0x80) && ((p + 1) < pmax))
1938 { /* new is kanji */
1939 if (*q & 0x80)
1940 { /* old is also kanji */
1941 if (((0xFF & *q) != (0xFF & *p))
1942 || ((0xFF & q[1]) != (0xFF & p[1])))
1944 /* both kanji, but not match */
1945 *buf++ = *p++;
1946 *buf++ = *p++;
1947 q += 2;
1948 continue;
1950 else
1951 { /* kanji match ? */
1952 if (!COLOR_EQS(*q, *p) || !COLOR_EQS(*(q+1), *(p+1)))
1954 /* code is match, but color is diff */
1955 *buf++ = *p++;
1956 *buf++ = *p++;
1957 q += 2;
1958 continue;
1960 /* really match ! */
1961 break;
1964 else
1965 { /* old is not kanji */
1966 *buf++ = *p++;
1967 *buf++ = *p++;
1968 q += 2;
1969 continue;
1972 else
1973 { /* new is not kanji */
1974 if (*q & 0x80)
1975 { /* old is kanji */
1976 *buf++ = *p++;
1977 q++;
1978 continue;
1981 #endif
1983 if (CHAR_EQS(q, p))
1985 /* Could be the second half of a double width character */
1986 if (p->nchars || q->nchars)
1987 break;
1989 *buf++ = *p++;
1990 q++;
1993 /* At this point, the buffer contains characters that do not match */
1994 if (buf != buffer) send_attr_str (buffer, buf);
1995 buf = buffer;
1997 if (n_spaces
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
2005 * some more.
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))
2012 *buf++ = *p++;
2013 q++;
2015 #else
2016 /* Kanji */
2017 while (p < pmax)
2019 if ((*p & 0x80) && ((p + 1) < pmax))
2020 { /* new is kanji */
2021 if (*q & 0x80)
2022 { /* old is also kanji */
2023 if (((0xFF & *q) == (0xFF & *p))
2024 && ((0xFF & q[1]) == (0xFF & p[1])))
2026 /* kanji match ? */
2027 if (!COLOR_EQS(*q, *p)
2028 || !COLOR_EQS(q[1], p[1]))
2029 break;
2031 *buf++ = *p++;
2032 q++;
2033 if (p >= pmax)
2035 *buf++ = 32;
2036 p++;
2037 break;
2039 else
2041 *buf++ = *p++;
2042 q++;
2043 continue;
2046 else break; /* both kanji, but not match */
2048 else break; /* old is not kanji */
2050 else
2051 { /* new is not kanji */
2052 if (*q & 0x80) break; /* old is kanji */
2053 if (!CHAR_EQS(*q, *p)) break;
2054 *buf++ = *p++;
2055 q++;
2058 #endif
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 */
2078 if (buf != buffer)
2080 if (q < qmax)
2082 if ((buf == last_buffered_match)
2083 && ((int) (buf - buffer) >= 5))
2085 forward_cursor ((unsigned int) (buf - buffer), row);
2087 else
2089 send_attr_str (buffer, buf);
2094 if (q < qmax)
2096 SLtt_reverse_video (COLOR_OF(space_char));
2097 del_eol ();
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);
2108 SLtt_end_insert ();
2110 #endif
2112 if (Automatic_Margins && (Cursor_c + 1 >= SLtt_Screen_Cols)) Cursor_Set = 0;
2115 static void get_color_info (void)
2117 char *fg, *bg;
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"));
2129 #endif
2131 if (-1 == get_default_colors (&fg, &bg))
2132 return;
2134 /* Check to see if application has already set them. */
2135 if (Color_0_Modified)
2136 return;
2138 SLtt_set_color (0, NULL, fg, bg);
2139 SLtt_set_color (1, NULL, bg, fg);
2142 /* termcap stuff */
2144 #ifdef __unix__
2146 static int Termcap_Initalized = 0;
2148 /* #define USE_TERMCAP 1 */
2149 #ifdef USE_TERMCAP
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 *);
2158 #else
2159 /* Terminfo */
2160 static SLterminfo_Type *Terminfo;
2161 #endif
2163 #define TGETFLAG(x) (SLtt_tgetflag(x) > 0)
2165 static char *fixup_tgetstr (char *what)
2167 register char *w, *w1;
2168 char *wsave;
2170 if (what == NULL)
2171 return NULL;
2173 /* Check for AIX brain-damage */
2174 if (*what == '@')
2175 return NULL;
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 $<...> */
2184 w = what;
2185 while (*w) if ((*w++ == '$') && (*w == '<'))
2187 w1 = w - 1;
2188 while (*w && (*w != '>')) w++;
2189 if (*w == 0) break;
2190 w++;
2191 wsave = w1;
2192 while ((*w1++ = *w++) != 0);
2193 w = wsave;
2196 if (*what == 0) what = NULL;
2197 return what;
2200 char *SLtt_tgetstr (char *cap)
2202 char *s;
2203 #ifdef USE_TERMCAP
2204 char area_buf[4096];
2205 char *area;
2206 #endif
2207 if (Termcap_Initalized == 0)
2208 return NULL;
2210 #ifdef USE_TERMCAP
2211 /* tmp_area = &Termcap_String_Buf; */
2212 area = area_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");
2220 #else
2221 s = _pSLtt_tigetstr (Terminfo, cap);
2222 #endif
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"))
2229 return s;
2231 s = fixup_tgetstr (s);
2232 #ifdef USE_TERMCAP
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
2237 * copy of it.
2239 * Yes, this introduces a leak...
2241 s = SLmake_string (s);
2243 #endif
2244 return s;
2247 int SLtt_tgetnum (char *s)
2249 if (Termcap_Initalized == 0)
2250 return -1;
2251 #ifdef USE_TERMCAP
2252 return tgetnum (s);
2253 #else
2254 return _pSLtt_tigetnum (Terminfo, s);
2255 #endif
2258 int SLtt_tgetflag (char *s)
2260 if (Termcap_Initalized == 0)
2261 return -1;
2262 #ifdef USE_TERMCAP
2263 return tgetflag (s);
2264 #else
2265 return _pSLtt_tigetflag (Terminfo, s);
2266 #endif
2269 #if 0
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++);
2278 return 0;
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");
2289 else
2290 tt_sprintf(buf, cap, row, col);
2291 return buf;
2293 #endif
2295 static int Vt100_Like = 0;
2297 void SLtt_get_terminfo (void)
2299 char *term;
2300 int status;
2302 term = getenv ("TERM");
2303 if (term == NULL)
2304 SLang_exit_error("TERM environment variable needs set.");
2306 if (0 == (status = SLtt_initialize (term)))
2307 return;
2309 if (status == -1)
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\
2315 termcap entry.",
2316 term);
2319 if (status == -2)
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)
2331 char *t, ch;
2332 int is_xterm;
2333 int almost_vtxxx;
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);
2344 if (term == NULL)
2346 term = getenv ("TERM");
2347 if (term == NULL)
2348 return -1;
2351 if (_pSLsecure_issetugid ()
2352 && ((term[0] == '.') || (NULL != strchr(term, '/'))))
2353 return -1;
2355 Linux_Console = (!strncmp (term, "linux", 5)
2356 # ifdef linux
2357 || !strncmp(term, "con", 3)
2358 # endif
2361 QANSI_Console = !strncmp (term, "qansi-m", 7);
2363 t = term;
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
2373 || Linux_Console
2374 || is_xterm
2375 || !strcmp (term, "screen"));
2377 # ifndef USE_TERMCAP
2378 if (NULL == (Terminfo = _pSLtt_tigetent (term)))
2380 if (almost_vtxxx) /* Special cases. */
2382 int vt102 = 1;
2383 if (!strcmp (term, "vt100")) vt102 = 0;
2384 get_color_info ();
2385 SLtt_set_term_vtxxx (&vt102);
2386 (void) SLtt_get_screen_size ();
2387 return 0;
2389 return -1;
2391 # else /* USE_TERMCAP */
2392 if (1 != tgetent(Termcap_Buf, term))
2393 return -1;
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'))
2430 || Linux_Console
2431 || is_xterm
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)))
2446 if (is_xterm
2447 || Linux_Console
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")))
2472 && is_xterm)
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 */
2485 if (Vt100_Like)
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))
2496 #if 0
2497 Start_Alt_Chars_Str = "\016";
2498 End_Alt_Chars_Str = "\017";
2499 Enable_Alt_Char_Set = "\033(B\033)0";
2500 #else
2501 Start_Alt_Chars_Str = "\033(0";
2502 End_Alt_Chars_Str = "\033(B";
2503 Enable_Alt_Char_Set = "";
2504 #endif
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;
2515 #ifdef AMIGA
2516 Enable_Alt_Char_Set = Start_Alt_Chars_Str = End_Alt_Chars_Str = NULL;
2517 #endif
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");
2541 # if 0
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);
2547 # endif
2549 Automatic_Margins = TGETFLAG ("am");
2550 /* No_Move_In_Standout = !TGETFLAG ("ms"); */
2551 # ifdef HP_GLITCH_CODE
2552 Has_HP_Glitch = TGETFLAG ("xs");
2553 # else
2554 Worthless_Highlight = TGETFLAG ("xs");
2555 # endif
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,
2568 * but Sf uses BGR.
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;
2588 else
2590 #if 0
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;
2594 #else
2595 Color_Fg_Str = "\033[3%dm";
2596 Color_Bg_Str = "\033[4%dm";
2597 Max_Terminfo_Colors = 8;
2598 #endif
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
2608 || is_xterm
2609 # endif
2612 #endif
2613 get_color_info ();
2616 if ((Cls_Str == NULL)
2617 || (Curs_Pos_Str == NULL))
2618 return -2;
2620 return 0;
2623 #endif
2624 /* Unix */
2626 /* specific to vtxxx only */
2627 void SLtt_enable_cursor_keys (void)
2629 #ifdef __unix__
2630 if (Vt100_Like)
2631 #endif
2632 tt_write_string("\033=\033[?1l");
2635 #ifdef VMS
2636 int SLtt_initialize (char *term)
2638 SLtt_get_terminfo ();
2639 return 0;
2642 void SLtt_get_terminfo ()
2644 int zero = 0;
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;
2656 get_color_info ();
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 ();
2666 #endif
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;
2697 else
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();
2714 SLtt_end_insert();
2715 tt_write_string (Enable_Alt_Char_Set);
2716 Video_Initialized = 1;
2717 return 0;
2720 int SLtt_reset_video (void)
2722 SLtt_goto_rc (SLtt_Screen_Rows - 1, 0);
2723 Cursor_Set = 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;
2741 SLtt_erase_line ();
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;
2750 return 0;
2753 void SLtt_bold_video (void)
2755 tt_write_string (Bold_Vid_Str);
2758 int SLtt_set_mouse_mode (int mode, int force)
2760 char *term;
2762 if (force == 0)
2764 if (NULL == (term = (char *) getenv("TERM"))) return -1;
2765 if (strncmp ("xterm", term, 5))
2766 return -1;
2769 Mouse_Mode = (mode != 0);
2771 if (mode)
2772 tt_write_string ("\033[?9h");
2773 else
2774 tt_write_string ("\033[?9l");
2776 return 0;
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))
2793 return -1;
2795 tt_printf (Goto_Status_Line_Str, col, 0);
2796 tt_write_string (s);
2797 tt_write_string (Return_From_Status_Line_Str);
2798 return 0;
2801 void SLtt_get_screen_size (void)
2803 #ifdef VMS
2804 int status, code;
2805 unsigned short chan;
2806 $DESCRIPTOR(dev_dsc, "SYS$INPUT:");
2807 #endif
2808 int r = 0, c = 0;
2810 #ifdef TIOCGWINSZ
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;
2821 break;
2824 while (errno == EINTR);
2826 #endif
2828 #ifdef VMS
2829 status = sys$assign(&dev_dsc,&chan,0,0,0);
2830 if (status & 1)
2832 code = DVI$_DEVBUFSIZ;
2833 status = lib$getdvi(&code, &chan,0, &c, 0,0);
2834 if (!(status & 1))
2835 c = 80;
2836 code = DVI$_TT_PAGE;
2837 status = lib$getdvi(&code, &chan,0, &r, 0,0);
2838 if (!(status & 1))
2839 r = 24;
2840 sys$dassgn(chan);
2842 #endif
2844 if (r <= 0)
2846 char *s = getenv ("LINES");
2847 if (s != NULL) r = atoi (s);
2850 if (c <= 0)
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;
2869 else
2871 SLtt_Char_Type fgbg = get_brush_fgbg (0);
2872 if (GET_BG(fgbg) == SLSMG_COLOR_DEFAULT)
2873 Bce_Color_Offset = 0;
2874 else
2875 Bce_Color_Offset = 1;
2878 return Bce_Color_Offset;
2880 #endif
2882 int SLtt_utf8_enable (int mode)
2884 if (mode == -1)
2885 mode = _pSLutf8_mode;
2887 return _pSLtt_UTF8_Mode = mode;
2890 int SLtt_is_utf8_mode (void)
2892 int mode = _pSLtt_UTF8_Mode;
2893 if (mode == -1)
2894 mode = _pSLutf8_mode;
2896 return mode;