separated out history section names to history.h
[midnight-commander.git] / slang / slsmg.c
blobb8f38e268f87e85f13e4a4a4b23c30374d5f1815
1 /* SLang Screen management routines */
2 #include "slinclud.h"
4 #include <stdio.h>
5 #include <string.h>
6 #include "slang.h"
7 #include "_slang.h"
9 typedef struct
11 int n; /* number of chars written last time */
12 int flags; /* line untouched, etc... */
13 SLsmg_Char_Type *old, *neew;
14 #ifndef IBMPC_SYSTEM
15 unsigned long old_hash, new_hash;
16 #endif
18 Screen_Type;
20 #define TOUCHED 0x1
21 #define TRASHED 0x2
22 static int Screen_Trashed;
24 static Screen_Type SL_Screen[SLTT_MAX_SCREEN_ROWS];
25 static int Start_Col, Start_Row;
26 static unsigned int Screen_Cols, Screen_Rows;
27 static int This_Row, This_Col;
28 static SLsmg_Color_Type This_Color;
30 static int UTF8_Mode = -1;
32 #if SLTT_HAS_NON_BCE_SUPPORT && !defined(IBMPC_SYSTEM)
33 #define REQUIRES_NON_BCE_SUPPORT 1
34 static int Bce_Color_Offset;
35 #endif
37 int SLsmg_Newline_Behavior = SLSMG_NEWLINE_IGNORED;
38 int SLsmg_Backspace_Moves = 0;
40 #if SLSMG_HAS_EMBEDDED_ESCAPE
41 /* If non-zero, interpret escape sequences ESC [ x m as an embedded set color
42 * sequence. The 'x' is a decimal integer that specifies the color. The sequence
43 * ends at m. Examples: \e[3m --> set color 3. \e[272m --> color=272.
44 * Note: These escape sequences are NOT ANSI, though similar. ANSI permits
45 * sequences such as \e[32;44m to set the foreground to green/blue. This interface
46 * will support such sequences, _but_ in will map such squences to the sum of
47 * the colors: \e[32;44m --> color (32+44)=76.
49 * In addition to 'm', ']' is also supported.
51 static int Embedded_Escape_Mode = 0;
52 int SLsmg_embedded_escape_mode (int mode)
54 int old_mode = Embedded_Escape_Mode;
55 Embedded_Escape_Mode = mode;
56 return old_mode;
59 /* This function gets called with u pointing at what may be '['. If it sucessfully
60 * parses the escape sequence, *up and the color will be updated.
62 static int parse_embedded_escape (SLuchar_Type *u, SLuchar_Type *umax,
63 SLsmg_Color_Type default_color,
64 SLuchar_Type **up, SLsmg_Color_Type *colorp)
66 unsigned int val;
67 SLuchar_Type ch;
69 if ((u < umax) && (*u != '['))
70 return -1;
72 u++;
73 if ((u < umax) && ((*u == 'm') || (*u == ']')))
75 *colorp = default_color; /* ESC[m */
76 *up = u+1;
77 return 0;
80 val = 0;
81 while ((u < umax)
82 && (((ch = *u) >= '0') && (ch <= '9')))
84 val = 10*val + (ch - '0');
85 u++;
87 if ((u < umax) && ((*u == 'm') || (*u == ']')) && (val <= SLSMG_MAX_COLORS))
89 # ifdef REQUIRES_NON_BCE_SUPPORT
90 val += Bce_Color_Offset;
91 #endif
92 *colorp = (SLsmg_Color_Type) val;
93 *up = u + 1;
94 return 0;
96 return -1;
99 static void parse_embedded_set_color (SLuchar_Type *u, SLuchar_Type *umax,
100 SLsmg_Color_Type default_color)
102 SLsmg_Color_Type color = default_color;
104 while (u < umax)
106 if (*u++ == 033)
107 (void) parse_embedded_escape (u, umax, default_color, &u, &color);
109 if (color == default_color)
110 return;
112 #ifdef REQUIRES_NON_BCE_SUPPORT
113 color -= Bce_Color_Offset;
114 #endif
115 SLsmg_set_color (color);
117 #endif
119 /* Backward compatibility. Not used. */
120 /* int SLsmg_Newline_Moves; */
121 static int *tt_Screen_Rows = NULL;
122 static int *tt_Screen_Cols = NULL;
123 static int *tt_unicode_ok;
125 static void (*tt_normal_video)(void);
126 static void (*tt_goto_rc)(int, int);
127 static void (*tt_cls) (void);
128 static void (*tt_del_eol) (void);
129 static void (*tt_smart_puts) (SLsmg_Char_Type *, SLsmg_Char_Type *, int, int);
130 static int (*tt_flush_output) (void);
131 static int (*tt_reset_video) (void);
132 static int (*tt_init_video) (void);
134 #ifndef IBMPC_SYSTEM
135 static void (*tt_set_scroll_region)(int, int);
136 static void (*tt_reverse_index)(int);
137 static void (*tt_reset_scroll_region)(void);
138 static void (*tt_delete_nlines)(int);
139 #endif
141 #ifndef IBMPC_SYSTEM
142 static int *tt_Term_Cannot_Scroll;
143 static int *tt_Has_Alt_Charset;
144 static char **tt_Graphics_Char_Pairs;
145 #else
146 static int *tt_Has_Alt_Charset = NULL;
147 static char **tt_Graphics_Char_Pairs = NULL;
148 #endif
150 static int Smg_Inited;
152 /* This is necessary because the windoze run-time linker cannot perform
153 * relocations on its own.
155 static void init_tt_symbols (void)
157 tt_Screen_Rows = &SLtt_Screen_Rows;
158 tt_Screen_Cols = &SLtt_Screen_Cols;
159 tt_unicode_ok = &_pSLtt_UTF8_Mode;
161 tt_normal_video = SLtt_normal_video;
162 tt_goto_rc = SLtt_goto_rc;
163 tt_cls = SLtt_cls;
164 tt_del_eol = SLtt_del_eol;
165 tt_smart_puts = SLtt_smart_puts;
166 tt_flush_output = SLtt_flush_output;
167 tt_reset_video = SLtt_reset_video;
168 tt_init_video = SLtt_init_video;
170 #ifndef IBMPC_SYSTEM
171 tt_set_scroll_region = SLtt_set_scroll_region;
172 tt_reverse_index = SLtt_reverse_index;
173 tt_reset_scroll_region = SLtt_reset_scroll_region;
174 tt_delete_nlines = SLtt_delete_nlines;
175 #endif
177 #ifndef IBMPC_SYSTEM
178 tt_Term_Cannot_Scroll = &SLtt_Term_Cannot_Scroll;
179 tt_Has_Alt_Charset = &SLtt_Has_Alt_Charset;
180 tt_Graphics_Char_Pairs = &SLtt_Graphics_Char_Pairs;
181 #else
182 tt_Has_Alt_Charset = NULL;
183 tt_Graphics_Char_Pairs = NULL;
184 #endif
187 /* Unicode box drawing characters */
189 /* This lookup table is indexed by the vt100 characters */
190 static SLwchar_Type ACS_Map[128];
192 typedef struct
194 unsigned char vt100_char;
195 unsigned char ascii;
196 SLwchar_Type unicode;
198 ACS_Def_Type;
200 static SLCONST ACS_Def_Type UTF8_ACS_Map[] =
202 {'+', '>', 0x2192 }, /* RIGHTWARDS ARROW */
203 {',', '<', 0x2190 }, /* LEFTWARDS ARROW */
204 {'-', '^', 0x2191 }, /* UPWARDS ARROW */
205 {'.', 'v', 0x2193 }, /* DOWNWARDS ARROW */
206 {'0', '#', 0x25AE }, /* BLACK VERTICAL RECTANGLE */
207 {'`', '+', 0x25C6 }, /* BLACK DIAMOND */
208 {'a', ':', 0x2592 }, /* MEDIUM SHADE */
209 {'f', '\'', 0x00B0 },/* DEGREE SIGN */
210 {'g', '#', 0x00B1 }, /* PLUS-MINUS SIGN */
211 {'h', '#', 0x2592 }, /* MEDIUM SHADE */
212 {'i', '#', 0x2603 }, /* SNOWMAN */
213 {'j', '+', 0x2518 }, /* BOX DRAWINGS LIGHT UP AND LEFT */
214 {'k', '+', 0x2510 }, /* BOX DRAWINGS LIGHT DOWN AND LEFT */
215 {'l', '+', 0x250c }, /* BOX DRAWINGS LIGHT DOWN AND RIGHT */
216 {'m', '+', 0x2514 }, /* BOX DRAWINGS LIGHT UP AND RIGHT */
217 {'n', '+', 0x253C }, /* BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */
218 {'o', '~', 0x23BA }, /* HORIZONTAL SCAN LINE-1 */
219 {'p', '-', 0x23BB }, /* HORIZONTAL SCAN LINE-3 (ncurses addition) */
220 {'q', '-', 0x2500 }, /* BOX DRAWINGS LIGHT HORIZONTAL */
221 {'r', '-', 0x23BC }, /* HORIZONTAL SCAN LINE-7 (ncurses addition) */
222 {'s', '_', 0x23BD }, /* HORIZONTAL SCAN LINE-9 */
223 {'t', '+', 0x251C }, /* BOX DRAWINGS LIGHT VERTICAL AND RIGHT */
224 {'u', '+', 0x2524 }, /* BOX DRAWINGS LIGHT VERTICAL AND LEFT */
225 {'v', '+', 0x2534 }, /* BOX DRAWINGS LIGHT UP AND HORIZONTAL */
226 {'w', '+', 0x252C }, /* BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */
227 {'x', '|', 0x2502 }, /* BOX DRAWINGS LIGHT VERTICAL */
228 {'y', '<', 0x2264 }, /* LESS-THAN OR EQUAL TO (ncurses addition) */
229 {'z', '>', 0x2265 }, /* GREATER-THAN OR EQUAL TO (ncurses addition) */
230 {'{', '*', 0x03C0 }, /* GREEK SMALL LETTER PI (ncurses addition) */
231 {'|', '!', 0x2260 }, /* NOT EQUAL TO (ncurses addition) */
232 {'}', 'f', 0x00A3 }, /* POUND SIGN (ncurses addition) */
233 {'~', 'o', 0x00B7 }, /* MIDDLE DOT */
234 {0, 0, 0}
237 #define ACS_MODE_NONE -1
238 #define ACS_MODE_AUTO 0
239 #define ACS_MODE_UNICODE 1
240 #define ACS_MODE_TERMINFO 2
241 #define ACS_MODE_ASCII 3
243 static int Current_ACS_Mode = ACS_MODE_NONE;
244 static void init_acs (int mode)
246 unsigned int i;
247 SLCONST ACS_Def_Type *acs;
249 if (Current_ACS_Mode == mode)
250 return;
252 for (i = 0; i < 0x80; i++)
253 ACS_Map[i] = ' ';
255 if (mode == ACS_MODE_AUTO)
257 if (UTF8_Mode &&
258 (tt_unicode_ok != NULL) && (*tt_unicode_ok > 0))
259 mode = ACS_MODE_UNICODE;
260 else
261 mode = ACS_MODE_TERMINFO;
264 switch (mode)
266 case ACS_MODE_UNICODE:
267 SLsmg_Display_Eight_Bit = 0xA0;
268 acs = UTF8_ACS_Map;
269 while (acs->vt100_char != 0)
271 ACS_Map[acs->vt100_char] = acs->unicode;
272 acs++;
274 break;
276 case ACS_MODE_TERMINFO:
277 if ((tt_Has_Alt_Charset != NULL)
278 && *tt_Has_Alt_Charset
279 && (tt_Graphics_Char_Pairs != NULL)
280 && (*tt_Graphics_Char_Pairs != NULL))
282 unsigned char *p = (unsigned char *) *tt_Graphics_Char_Pairs;
283 unsigned char *pmax = p + strlen ((char *) p);
285 while (p < pmax)
287 unsigned char ch = *p++;
288 ACS_Map[ch & 0x7F] = *p++;
290 break;
292 mode = ACS_MODE_ASCII;
293 /* drop */
294 case ACS_MODE_ASCII:
295 default:
296 acs = UTF8_ACS_Map;
297 while (acs->vt100_char != 0)
299 ACS_Map[acs->vt100_char] = acs->ascii;
300 acs++;
302 break;
305 Current_ACS_Mode = mode;
308 static void blank_line (SLsmg_Char_Type *c, unsigned int n, SLwchar_Type wch)
310 SLsmg_Char_Type *cmax = c + n;
311 SLsmg_Color_Type color = This_Color;
313 memset ((char *)c, 0, n*sizeof(SLsmg_Char_Type));
314 while (c < cmax)
316 c->nchars = 1;
317 c->wchars[0] = wch;
318 c->color = color;
319 c++;
323 static void clear_region (int row, int n, SLwchar_Type ch)
325 int i;
326 int imax = row + n;
328 if (imax > (int) Screen_Rows) imax = (int) Screen_Rows;
329 if (row < 0)
330 row = 0;
332 for (i = row; i < imax; i++)
334 blank_line (SL_Screen[i].neew, Screen_Cols, ch);
335 SL_Screen[i].flags |= TOUCHED;
339 void SLsmg_erase_eol (void)
341 int r, c;
343 if (Smg_Inited == 0) return;
345 c = This_Col - Start_Col;
346 r = This_Row - Start_Row;
348 if ((r < 0) || (r >= (int)Screen_Rows)) return;
349 if (c < 0) c = 0; else if (c >= (int)Screen_Cols) return;
350 blank_line (SL_Screen[This_Row].neew + c , Screen_Cols - c, 0x20);
351 SL_Screen[This_Row].flags |= TOUCHED;
354 static void scroll_up (void)
356 unsigned int i, imax;
357 SLsmg_Char_Type *neew;
359 neew = SL_Screen[0].neew;
360 imax = Screen_Rows - 1;
361 for (i = 0; i < imax; i++)
363 SL_Screen[i].neew = SL_Screen[i + 1].neew;
364 SL_Screen[i].flags |= TOUCHED;
366 SL_Screen[i].neew = neew;
367 SL_Screen[i].flags |= TOUCHED;
368 blank_line (neew, Screen_Cols, 0x20);
369 This_Row--;
372 void SLsmg_gotorc (int r, int c)
374 This_Row = r;
375 This_Col = c;
378 int SLsmg_get_row (void)
380 return This_Row;
383 int SLsmg_get_column (void)
385 return This_Col;
388 void SLsmg_erase_eos (void)
390 if (Smg_Inited == 0) return;
392 SLsmg_erase_eol ();
393 clear_region (This_Row + 1, (int)Screen_Rows, 0x20);
396 static int This_Alt_Char;
398 void SLsmg_set_char_set (int i)
400 #ifdef IBMPC_SYSTEM
401 (void) i;
402 #else
403 if (i != 0)
404 This_Alt_Char = SLSMG_ACS_MASK;
405 else This_Alt_Char = 0;
407 This_Color &= SLSMG_COLOR_MASK;
408 This_Color |= This_Alt_Char;
409 #endif
412 void SLsmg_set_color (SLsmg_Color_Type color)
414 #ifdef REQUIRES_NON_BCE_SUPPORT
415 color += Bce_Color_Offset;
416 #endif
417 This_Color = color | This_Alt_Char;
420 void SLsmg_reverse_video (void)
422 SLsmg_set_color (1);
425 void SLsmg_normal_video (void)
427 SLsmg_set_color (0);
430 static int point_visible (int col_too)
432 return ((This_Row >= Start_Row) && (This_Row < Start_Row + (int)Screen_Rows)
433 && ((col_too == 0)
434 || ((This_Col >= Start_Col)
435 && (This_Col < Start_Col + (int)Screen_Cols))));
438 #define NEXT_CHAR_CELL \
440 if (p < pmax) \
442 if ((p->nchars != i) || (p->color != color)) flags |= TOUCHED; \
443 p->nchars = i; \
444 p->color = color; \
445 p++; \
447 i = 0; \
448 col++; \
449 } (void) 0
452 #define ADD_TO_CHAR_CELL(wc) \
454 if ((p < pmax) && (p->wchars[i] != wc)) \
456 p->wchars[i] = wc; \
457 flags |= TOUCHED; \
459 i++; \
460 } (void) 0
462 #define ADD_CHAR_OR_BREAK(ch) \
463 if (col >= start_col) \
465 if (i != 0) NEXT_CHAR_CELL; \
466 if (last_was_double_width) \
468 last_was_double_width = 0; \
469 NEXT_CHAR_CELL; \
471 if (col >= max_col) break; \
472 ADD_TO_CHAR_CELL(ch); \
474 else col++
477 void SLsmg_write_chars (unsigned char *u, unsigned char *umax)
479 SLsmg_Char_Type *p, *pmax;
480 SLsmg_Color_Type color;
481 int flags;
482 int col, start_col, max_col;
483 int newline_flag;
484 int utf8_mode = UTF8_Mode;
485 unsigned char display_8bit;
486 int last_was_double_width = 0;
487 int alt_char_set_flag;
488 unsigned int i;
489 #if SLSMG_HAS_EMBEDDED_ESCAPE
490 SLsmg_Color_Type default_color;
491 #endif
492 if (Smg_Inited == 0) return;
494 display_8bit = (unsigned char) SLsmg_Display_Eight_Bit;
495 if (utf8_mode)
496 display_8bit = 0xA0;
498 color = This_Color;
499 /* If we are using unicode characters for the line drawing characters, then
500 * do not attempt to use the terminals alternate character set
502 alt_char_set_flag = (color & SLSMG_ACS_MASK);
503 if (Current_ACS_Mode == ACS_MODE_UNICODE)
504 color = color & ~SLSMG_ACS_MASK;
506 #if SLSMG_HAS_EMBEDDED_ESCAPE
507 default_color = color; /* used for ESC[m */
508 #endif
510 top: /* get here only on newline */
512 newline_flag = 0;
513 start_col = Start_Col;
515 if (point_visible (0) == 0) return;
517 col = This_Col;
518 max_col = start_col + Screen_Cols;
520 p = SL_Screen[This_Row - Start_Row].neew;
521 pmax = p + Screen_Cols;
523 if (col >= start_col)
525 p += (col - start_col);
526 if ((p < pmax) && (p->nchars == 0))
528 /* It looks like we are about to overwrite the right side of a
529 * double width character.
531 if (col > start_col)
533 p--;
534 p->nchars = 1;
535 p->wchars[0] = ' ';
536 p++;
542 flags = SL_Screen[This_Row - Start_Row].flags;
543 i = 0;
545 while (u < umax)
547 SLwchar_Type wc;
548 unsigned int width, nconsumed;
550 if (*u < (SLuchar_Type) 0x80) /* ASCII */
552 unsigned char ch;
554 ch = (unsigned char) *u++;
556 if (alt_char_set_flag)
558 wc = ACS_Map[ch];
559 ADD_CHAR_OR_BREAK(wc);
560 continue;
563 if ((ch >= (SLuchar_Type)0x20) && (ch < (SLuchar_Type)0x7F))
565 ADD_CHAR_OR_BREAK(ch);
566 continue;
569 if ((ch == '\t') && (SLsmg_Tab_Width > 0))
573 if (col < start_col)
574 col++;
575 else
577 ADD_CHAR_OR_BREAK(' ');
578 NEXT_CHAR_CELL;
581 while (col % SLsmg_Tab_Width);
582 continue;
585 if ((ch == '\n')
586 && (SLsmg_Newline_Behavior != SLSMG_NEWLINE_PRINTABLE))
588 newline_flag = 1;
589 break;
592 if ((ch == 0x8) && SLsmg_Backspace_Moves)
594 if (col != 0)
596 if (i != 0)
598 NEXT_CHAR_CELL;
599 col--;
600 p--;
602 col--;
603 p--;
605 continue;
607 #if SLSMG_HAS_EMBEDDED_ESCAPE
608 if ((ch == 033) && Embedded_Escape_Mode)
610 SLsmg_Color_Type next_color;
612 if (0 == parse_embedded_escape (u, umax, default_color, &u, &next_color))
614 if (i != 0)
615 NEXT_CHAR_CELL;
616 color = next_color;
617 continue;
620 #endif
621 ADD_CHAR_OR_BREAK('^');
622 if (ch == 127) ch = '?'; else ch = ch + '@';
623 ADD_CHAR_OR_BREAK (ch);
624 continue;
627 nconsumed = 1;
628 if ((utf8_mode == 0)
629 || (NULL == SLutf8_decode (u, umax, &wc, &nconsumed)))
631 unsigned int ii, jj;
632 unsigned char hexbuf[8];
634 if ((utf8_mode == 0)
635 && display_8bit && (*u >= display_8bit))
637 ADD_CHAR_OR_BREAK(*u);
639 else for (ii = 0; ii < nconsumed; ii++)
641 sprintf ((char *)hexbuf, "<%02X>", u[ii]);
642 for (jj = 0; jj < 4; jj++)
644 ADD_CHAR_OR_BREAK (hexbuf[jj]);
647 u += nconsumed;
648 continue;
651 u += nconsumed;
652 if (wc < (SLwchar_Type)display_8bit)
654 unsigned char hexbuf[8];
655 unsigned int jj;
657 sprintf ((char *)hexbuf, "<%02X>", (unsigned char) wc);
658 for (jj = 0; jj < 4; jj++)
660 ADD_CHAR_OR_BREAK (hexbuf[jj]);
662 continue;
665 width = SLwchar_wcwidth (wc);
666 if (width == 0)
668 /* Combining character--- must follow non-zero width char */
669 if (i == 0)
670 continue;
671 if (i < SLSMG_MAX_CHARS_PER_CELL)
673 ADD_TO_CHAR_CELL (wc);
675 continue;
678 if (width == 2)
680 if (col + 2 <= start_col)
682 col += 2;
683 continue;
686 if (col + 2 > max_col)
688 ADD_CHAR_OR_BREAK('>');
689 break;
692 if (col == start_col - 1)
694 /* double width character is clipped at left part of screen.
695 * So, display right edge as a space */
696 col++;
697 ADD_CHAR_OR_BREAK('<');
698 continue;
701 ADD_CHAR_OR_BREAK(wc);
702 last_was_double_width = 1;
703 continue;
706 ADD_CHAR_OR_BREAK(wc);
709 if (i != 0)
711 NEXT_CHAR_CELL;
714 if (last_was_double_width)
716 if (col < max_col)
717 NEXT_CHAR_CELL;
718 last_was_double_width = 0;
720 else if ((col < max_col) && (p->nchars == 0))
722 /* The left side of a double with character was overwritten */
723 p->nchars = 1;
724 p->wchars[0] = ' ';
726 SL_Screen[This_Row - Start_Row].flags = flags;
727 This_Col = col;
729 /* Why would u be NULL here?? */
731 if (SLsmg_Newline_Behavior == SLSMG_NEWLINE_IGNORED)
733 #if SLSMG_HAS_EMBEDDED_ESCAPE
734 if (Embedded_Escape_Mode && (u != NULL))
735 parse_embedded_set_color (u, umax, default_color);
736 #endif
737 return;
740 if (newline_flag == 0)
742 #if SLSMG_HAS_EMBEDDED_ESCAPE
743 SLuchar_Type *usave = u;
744 #endif
745 if (u == NULL)
746 return;
748 while (u < umax)
750 if (*u == '\n') break;
751 u++;
753 if (u >= umax)
755 #if SLSMG_HAS_EMBEDDED_ESCAPE
756 if (Embedded_Escape_Mode)
757 parse_embedded_set_color (usave, umax, default_color);
758 #endif
759 return;
761 u++;
764 This_Row++;
765 This_Col = 0;
766 if (This_Row == Start_Row + (int)Screen_Rows)
768 if (SLsmg_Newline_Behavior == SLSMG_NEWLINE_SCROLLS) scroll_up ();
770 goto top;
774 void SLsmg_write_nchars (char *str, unsigned int len)
776 SLsmg_write_chars ((unsigned char *) str, (unsigned char *)str + len);
779 void SLsmg_write_string (char *str)
781 SLsmg_write_chars ((unsigned char *)str,
782 (unsigned char *)str + strlen (str));
785 void SLsmg_write_nstring (char *str, unsigned int n)
787 unsigned int width;
788 unsigned char *blank = (unsigned char *)" ";
789 unsigned char *u = (unsigned char *)str;
791 /* Avoid a problem if a user accidently passes a negative value */
792 if ((int) n < 0)
793 return;
795 if (u == NULL) width = 0;
796 else
798 unsigned char *umax;
800 width = strlen ((char *)u);
801 if (UTF8_Mode)
802 umax = SLutf8_skip_chars (u, u+width, n, &width, 0);
803 else
805 if (width > n) width = n;
806 umax = u + width;
808 SLsmg_write_chars (u, umax);
811 while (width++ < n) SLsmg_write_chars (blank, blank+1);
814 void SLsmg_write_wrapped_string (SLuchar_Type *u, int r, int c,
815 unsigned int dr, unsigned int dc,
816 int fill)
818 int maxc = (int) dc;
819 unsigned char *p, *pmax;
820 int utf8_mode = UTF8_Mode;
822 if ((dr == 0) || (dc == 0)) return;
823 p = u;
824 pmax = u + strlen ((char *)u);
826 dc = 0;
827 while (1)
829 unsigned char ch = *p;
830 if ((ch == 0) || (ch == '\n'))
832 int diff;
834 diff = maxc - (int) dc;
836 SLsmg_gotorc (r, c);
837 SLsmg_write_chars (u, p);
838 if (fill && (diff > 0))
840 unsigned char *blank = (unsigned char *)" ";
841 while (diff--) SLsmg_write_chars (blank, blank+1);
843 if ((ch == 0) || (dr == 1)) break;
845 r++;
846 dc = 0;
847 dr--;
848 p++;
849 u = p;
850 continue;
853 if ((int) dc == maxc)
855 SLsmg_gotorc (r, c);
856 SLsmg_write_chars (u, p);
857 if (dr == 1) break;
859 r++;
860 dc = 0;
861 dr--;
862 u = p;
863 continue;
866 dc++;
867 if (utf8_mode)
868 p = SLutf8_skip_chars (p, pmax, 1, NULL, 0);
869 else
870 p++;
874 int SLsmg_Tab_Width = 8;
876 /* Minimum value for which eight bit char is displayed as is. */
878 #ifndef IBMPC_SYSTEM
879 int SLsmg_Display_Eight_Bit = 160;
880 #else
881 int SLsmg_Display_Eight_Bit = 128;
882 #endif
884 void SLsmg_write_char (SLwchar_Type ch)
886 unsigned char u[SLUTF8_MAX_MBLEN];
887 unsigned char *umax;
889 if ((ch < 0x80) || (UTF8_Mode == 0))
891 u[0] = (unsigned char) ch;
892 SLsmg_write_chars (u, u+1);
893 return;
895 if (NULL == (umax = SLutf8_encode (ch, u, SLUTF8_MAX_MBLEN)))
896 return;
897 SLsmg_write_chars (u, umax);
900 static int Cls_Flag;
902 void SLsmg_cls (void)
904 int tac;
905 if (Smg_Inited == 0) return;
907 tac = This_Alt_Char; This_Alt_Char = 0;
908 SLsmg_set_color (0);
909 clear_region (0, (int)Screen_Rows, 0x20);
910 This_Alt_Char = tac;
911 SLsmg_set_color (0);
912 Cls_Flag = 1;
914 #if 0
915 static void do_copy (SLsmg_Char_Type *a, SLsmg_Char_Type *b)
917 SLsmg_Char_Type *amax = a + Screen_Cols;
919 while (a < amax) *a++ = *b++;
921 #endif
923 #ifndef IBMPC_SYSTEM
924 int SLsmg_Scroll_Hash_Border = 0;
925 static unsigned long compute_hash (SLsmg_Char_Type *c, unsigned int n)
927 SLsmg_Char_Type *csave, *cmax;
928 int is_blank = 2;
930 c += SLsmg_Scroll_Hash_Border;
931 csave = c;
932 cmax = c + (n - SLsmg_Scroll_Hash_Border);
934 while ((c < cmax) && is_blank)
936 if ((c->wchars[0] != 32) || (c->nchars != 1))
937 is_blank--;
938 c++;
940 if (is_blank) return 0;
942 return _pSLstring_hash ((unsigned char *)csave, (unsigned char *)cmax);
945 static unsigned long Blank_Hash;
947 static int try_scroll_down (int rmin, int rmax)
949 int i, r1, r2, di, j;
950 unsigned long hash;
951 int did_scroll;
952 SLsmg_Color_Type color;
953 SLsmg_Char_Type *tmp;
954 int ignore;
956 did_scroll = 0;
957 for (i = rmax; i > rmin; i--)
959 hash = SL_Screen[i].new_hash;
960 if (hash == Blank_Hash) continue;
962 if ((hash == SL_Screen[i].old_hash)
963 #if 0
964 || ((i + 1 < Screen_Rows) && (hash == SL_Screen[i + 1].old_hash))
965 || ((i - 1 > rmin) && (SL_Screen[i].old_hash == SL_Screen[i - 1].new_hash))
966 #endif
968 continue;
970 for (j = i - 1; j >= rmin; j--)
972 if (hash == SL_Screen[j].old_hash) break;
974 if (j < rmin) continue;
976 r2 = i; /* end scroll region */
978 di = i - j;
979 j--;
980 ignore = 0;
981 while ((j >= rmin) && (SL_Screen[j].old_hash == SL_Screen[j + di].new_hash))
983 if (SL_Screen[j].old_hash == Blank_Hash) ignore++;
984 j--;
986 r1 = j + 1;
988 /* If this scroll only scrolls this line into place, don't do it.
990 if ((di > 1) && (r1 + di + ignore == r2)) continue;
992 /* If there is anything in the scrolling region that is ok, abort the
993 * scroll.
996 for (j = r1; j <= r2; j++)
998 if ((SL_Screen[j].old_hash != Blank_Hash)
999 && (SL_Screen[j].old_hash == SL_Screen[j].new_hash))
1001 /* See if the scroll is happens to scroll this one into place. */
1002 if ((j + di > r2) || (SL_Screen[j].old_hash != SL_Screen[j + di].new_hash))
1003 break;
1006 if (j <= r2) continue;
1008 color = This_Color; This_Color = 0;
1009 did_scroll = 1;
1010 (*tt_normal_video) ();
1011 (*tt_set_scroll_region) (r1, r2);
1012 (*tt_goto_rc) (0, 0);
1013 (*tt_reverse_index) (di);
1014 (*tt_reset_scroll_region) ();
1015 /* Now we have a hole in the screen.
1016 * Make the virtual screen look like it.
1018 * Note that if the terminal does not support BCE, then we have
1019 * no idea what color the hole is. So, for this case, we do not
1020 * want to add Bce_Color_Offset to This_Color since if Bce_Color_Offset
1021 * is non-zero, then This_Color = 0 does not match any valid color
1022 * obtained by adding Bce_Color_Offset.
1024 for (j = r1; j <= r2; j++) SL_Screen[j].flags = TOUCHED;
1026 while (di--)
1028 tmp = SL_Screen[r2].old;
1029 for (j = r2; j > r1; j--)
1031 SL_Screen[j].old = SL_Screen[j - 1].old;
1032 SL_Screen[j].old_hash = SL_Screen[j - 1].old_hash;
1034 SL_Screen[r1].old = tmp;
1035 blank_line (SL_Screen[r1].old, Screen_Cols, 0x20);
1036 SL_Screen[r1].old_hash = Blank_Hash;
1037 r1++;
1039 This_Color = color;
1042 return did_scroll;
1045 static int try_scroll_up (int rmin, int rmax)
1047 int i, r1, r2, di, j;
1048 unsigned long hash;
1049 int did_scroll;
1050 SLsmg_Color_Type color;
1051 SLsmg_Char_Type *tmp;
1052 int ignore;
1054 did_scroll = 0;
1055 for (i = rmin; i < rmax; i++)
1057 hash = SL_Screen[i].new_hash;
1058 if (hash == Blank_Hash) continue;
1059 if (hash == SL_Screen[i].old_hash)
1060 continue;
1061 /* find a match further down screen */
1062 for (j = i + 1; j <= rmax; j++)
1064 if (hash == SL_Screen[j].old_hash) break;
1066 if (j > rmax) continue;
1068 r1 = i; /* beg scroll region */
1069 di = j - i; /* number of lines to scroll */
1070 j++; /* since we know this is a match */
1072 /* find end of scroll region */
1073 ignore = 0;
1074 while ((j <= rmax) && (SL_Screen[j].old_hash == SL_Screen[j - di].new_hash))
1076 if (SL_Screen[j].old_hash == Blank_Hash) ignore++;
1077 j++;
1079 r2 = j - 1; /* end of scroll region */
1081 /* If this scroll only scrolls this line into place, don't do it.
1083 if ((di > 1) && (r1 + di + ignore == r2)) continue;
1085 /* If there is anything in the scrolling region that is ok, abort the
1086 * scroll.
1089 for (j = r1; j <= r2; j++)
1091 if ((SL_Screen[j].old_hash != Blank_Hash)
1092 && (SL_Screen[j].old_hash == SL_Screen[j].new_hash))
1094 if ((j - di < r1) || (SL_Screen[j].old_hash != SL_Screen[j - di].new_hash))
1095 break;
1099 if (j <= r2) continue;
1101 did_scroll = 1;
1103 /* See the above comments about BCE */
1104 color = This_Color; This_Color = 0;
1105 (*tt_normal_video) ();
1106 (*tt_set_scroll_region) (r1, r2);
1107 (*tt_goto_rc) (0, 0); /* relative to scroll region */
1108 (*tt_delete_nlines) (di);
1109 (*tt_reset_scroll_region) ();
1110 /* Now we have a hole in the screen. Make the virtual screen look
1111 * like it.
1113 for (j = r1; j <= r2; j++) SL_Screen[j].flags = TOUCHED;
1115 while (di--)
1117 tmp = SL_Screen[r1].old;
1118 for (j = r1; j < r2; j++)
1120 SL_Screen[j].old = SL_Screen[j + 1].old;
1121 SL_Screen[j].old_hash = SL_Screen[j + 1].old_hash;
1123 SL_Screen[r2].old = tmp;
1124 blank_line (SL_Screen[r2].old, Screen_Cols, ' ');
1125 SL_Screen[r2].old_hash = Blank_Hash;
1126 r2--;
1128 This_Color = color;
1130 return did_scroll;
1133 static void try_scroll (void)
1135 int r1, rmin, rmax;
1136 int num_up, num_down;
1137 /* find region limits. */
1139 for (rmax = Screen_Rows - 1; rmax > 0; rmax--)
1141 if (SL_Screen[rmax].new_hash != SL_Screen[rmax].old_hash)
1143 r1 = rmax - 1;
1144 if ((r1 == 0)
1145 || (SL_Screen[r1].new_hash != SL_Screen[r1].old_hash))
1146 break;
1148 rmax = r1;
1152 for (rmin = 0; rmin < rmax; rmin++)
1154 if (SL_Screen[rmin].new_hash != SL_Screen[rmin].old_hash)
1156 r1 = rmin + 1;
1157 if ((r1 == rmax)
1158 || (SL_Screen[r1].new_hash != SL_Screen[r1].old_hash))
1159 break;
1161 rmin = r1;
1165 /* Below, we have two scrolling algorithms. The first has the effect of
1166 * scrolling lines down. This is usually appropriate when one moves
1167 * up the display, e.g., with the UP arrow. The second algorithm is
1168 * appropriate for going the other way. It is important to choose the
1169 * correct one.
1172 num_up = 0;
1173 for (r1 = rmin; r1 < rmax; r1++)
1175 if (SL_Screen[r1].new_hash == SL_Screen[r1 + 1].old_hash)
1176 num_up++;
1179 num_down = 0;
1180 for (r1 = rmax; r1 > rmin; r1--)
1182 if (SL_Screen[r1 - 1].old_hash == SL_Screen[r1].new_hash)
1183 num_down++;
1186 if (num_up > num_down)
1188 if (try_scroll_up (rmin, rmax))
1189 return;
1191 (void) try_scroll_down (rmin, rmax);
1193 else
1195 if (try_scroll_down (rmin, rmax))
1196 return;
1198 (void) try_scroll_up (rmin, rmax);
1201 #endif /* NOT IBMPC_SYSTEM */
1203 #ifdef REQUIRES_NON_BCE_SUPPORT
1204 static void adjust_colors (void)
1206 int bce;
1207 unsigned int i;
1209 bce = Bce_Color_Offset;
1210 Bce_Color_Offset = _pSLtt_get_bce_color_offset ();
1211 if (bce == Bce_Color_Offset)
1212 return;
1214 for (i = 0; i < Screen_Rows; i++)
1216 SLsmg_Char_Type *s, *smax;
1218 SL_Screen[i].flags |= TRASHED;
1219 s = SL_Screen[i].neew;
1220 smax = s + Screen_Cols;
1222 while (s < smax)
1224 SLsmg_Color_Type color = s->color;
1225 int acs = color & SLSMG_ACS_MASK;
1226 color = (color & SLSMG_COLOR_MASK) + (Bce_Color_Offset - bce);
1227 if (color < SLSMG_MAX_COLORS)
1228 s->color = color | acs;
1230 s++;
1234 #endif
1236 void SLsmg_refresh (void)
1238 unsigned int i;
1239 #ifndef IBMPC_SYSTEM
1240 int trashed = 0;
1241 #endif
1242 int r, c;
1244 if (Smg_Inited == 0) return;
1246 if (Screen_Trashed)
1248 Cls_Flag = 1;
1249 for (i = 0; i < Screen_Rows; i++)
1250 SL_Screen[i].flags |= TRASHED;
1251 #ifdef REQUIRES_NON_BCE_SUPPORT
1252 adjust_colors ();
1253 #endif
1256 #ifndef IBMPC_SYSTEM
1257 for (i = 0; i < Screen_Rows; i++)
1259 if (SL_Screen[i].flags == 0) continue;
1260 SL_Screen[i].new_hash = compute_hash (SL_Screen[i].neew, Screen_Cols);
1261 trashed = 1;
1263 #endif
1265 if (Cls_Flag)
1267 (*tt_normal_video) (); (*tt_cls) ();
1269 #ifndef IBMPC_SYSTEM
1270 else if (trashed && (*tt_Term_Cannot_Scroll == 0)) try_scroll ();
1271 #endif
1273 for (i = 0; i < Screen_Rows; i++)
1275 if (SL_Screen[i].flags == 0) continue;
1277 if (Cls_Flag || SL_Screen[i].flags & TRASHED)
1279 SLsmg_Color_Type color = This_Color;
1281 if (Cls_Flag == 0)
1283 (*tt_goto_rc) (i, 0);
1284 (*tt_del_eol) ();
1286 This_Color = 0;
1287 blank_line (SL_Screen[i].old, Screen_Cols, 0x20);
1288 This_Color = color;
1291 (*tt_smart_puts) (SL_Screen[i].neew, SL_Screen[i].old, Screen_Cols, i);
1293 memcpy ((char *) SL_Screen[i].old, (char *) SL_Screen[i].neew,
1294 Screen_Cols * sizeof (SLsmg_Char_Type));
1296 SL_Screen[i].flags = 0;
1297 #ifndef IBMPC_SYSTEM
1298 SL_Screen[i].old_hash = SL_Screen[i].new_hash;
1299 #endif
1303 r = This_Row - Start_Row;
1304 c = This_Col - Start_Col;
1305 if (r < 0)
1307 r = 0;
1308 c = 0;
1310 else if (r >= (int)Screen_Rows)
1312 r = (int)Screen_Rows;
1313 c = (int)Screen_Cols-1;
1315 if (c < 0)
1316 c = 0;
1317 else if (c >= (int)Screen_Cols)
1318 c = (int)Screen_Cols-1;
1320 (*tt_goto_rc) (r,c);
1321 (void) (*tt_flush_output) ();
1322 Cls_Flag = 0;
1323 Screen_Trashed = 0;
1326 static int compute_clip (int row, int n, int box_start, int box_end,
1327 int *rmin, int *rmax)
1329 int row_max;
1331 if (n < 0) return 0;
1332 if (row >= box_end) return 0;
1333 row_max = row + n;
1334 if (row_max <= box_start) return 0;
1336 if (row < box_start) row = box_start;
1337 if (row_max >= box_end) row_max = box_end;
1338 *rmin = row;
1339 *rmax = row_max;
1340 return 1;
1343 void SLsmg_touch_lines (int row, unsigned int n)
1345 int i;
1346 int r1, r2;
1348 /* Allow this function to be called even when we are not initialied.
1349 * Calling this function is useful after calling SLtt_set_color
1350 * to force the display to be redrawn
1353 if (Smg_Inited == 0)
1354 return;
1356 if (0 == compute_clip (row, (int) n, Start_Row, Start_Row + Screen_Rows, &r1, &r2))
1357 return;
1359 r1 -= Start_Row;
1360 r2 -= Start_Row;
1361 for (i = r1; i < r2; i++)
1363 SL_Screen[i].flags |= TRASHED;
1367 void SLsmg_touch_screen (void)
1369 Screen_Trashed = 1;
1372 #ifndef IBMPC_SYSTEM
1373 # define BLOCK_SIGNALS SLsig_block_signals ()
1374 # define UNBLOCK_SIGNALS SLsig_unblock_signals ()
1375 #else
1376 # define BLOCK_SIGNALS (void)0
1377 # define UNBLOCK_SIGNALS (void)0
1378 #endif
1380 static int Smg_Suspended;
1381 int SLsmg_suspend_smg (void)
1383 BLOCK_SIGNALS;
1385 if (Smg_Suspended == 0)
1387 (*tt_reset_video) ();
1388 Smg_Suspended = 1;
1391 UNBLOCK_SIGNALS;
1392 return 0;
1395 int SLsmg_resume_smg (void)
1397 BLOCK_SIGNALS;
1399 if (Smg_Suspended == 0)
1401 UNBLOCK_SIGNALS;
1402 return 0;
1405 Smg_Suspended = 0;
1407 if (-1 == (*tt_init_video) ())
1409 UNBLOCK_SIGNALS;
1410 return -1;
1413 Cls_Flag = 1;
1414 SLsmg_touch_screen ();
1415 SLsmg_refresh ();
1417 UNBLOCK_SIGNALS;
1418 return 0;
1422 static void reset_smg (void)
1424 unsigned int i;
1425 if (Smg_Inited == 0)
1426 return;
1428 for (i = 0; i < Screen_Rows; i++)
1430 SLfree ((char *)SL_Screen[i].old);
1431 SLfree ((char *)SL_Screen[i].neew);
1432 SL_Screen[i].old = SL_Screen[i].neew = NULL;
1434 This_Alt_Char = This_Color = 0;
1435 Smg_Inited = 0;
1439 static int init_smg (void)
1441 unsigned int i, len;
1442 SLsmg_Char_Type *old, *neew;
1444 Smg_Inited = 0;
1446 #ifdef REQUIRES_NON_BCE_SUPPORT
1447 Bce_Color_Offset = _pSLtt_get_bce_color_offset ();
1448 #endif
1450 Screen_Rows = *tt_Screen_Rows;
1451 if (Screen_Rows > SLTT_MAX_SCREEN_ROWS)
1452 Screen_Rows = SLTT_MAX_SCREEN_ROWS;
1454 Screen_Cols = *tt_Screen_Cols;
1456 This_Col = This_Row = Start_Col = Start_Row = 0;
1458 This_Alt_Char = 0;
1459 SLsmg_set_color (0);
1460 Cls_Flag = 1;
1462 init_acs (ACS_MODE_AUTO);
1464 len = Screen_Cols + 3;
1465 for (i = 0; i < Screen_Rows; i++)
1467 if ((NULL == (old = (SLsmg_Char_Type *) SLmalloc (sizeof(SLsmg_Char_Type) * len)))
1468 || ((NULL == (neew = (SLsmg_Char_Type *) SLmalloc (sizeof(SLsmg_Char_Type) * len)))))
1470 SLfree ((char *) old);
1471 return -1;
1473 blank_line (old, len, ' ');
1474 blank_line (neew, len, ' ');
1475 SL_Screen[i].old = old;
1476 SL_Screen[i].neew = neew;
1477 SL_Screen[i].flags = 0;
1478 #ifndef IBMPC_SYSTEM
1479 Blank_Hash = compute_hash (old, Screen_Cols);
1480 SL_Screen[i].new_hash = SL_Screen[i].old_hash = Blank_Hash;
1481 #endif
1484 _pSLtt_color_changed_hook = SLsmg_touch_screen;
1485 Screen_Trashed = 1;
1486 Smg_Inited = 1;
1487 return 0;
1491 int SLsmg_init_smg (void)
1493 int ret;
1495 BLOCK_SIGNALS;
1497 if (tt_Screen_Rows == NULL)
1498 init_tt_symbols ();
1500 if (Smg_Inited)
1501 SLsmg_reset_smg ();
1503 if (UTF8_Mode == -1)
1504 UTF8_Mode = _pSLutf8_mode;
1506 if (-1 == (*tt_init_video) ())
1508 UNBLOCK_SIGNALS;
1509 return -1;
1512 if (-1 == (ret = init_smg ()))
1513 (void) (*tt_reset_video)();
1515 UNBLOCK_SIGNALS;
1516 return ret;
1519 int SLsmg_reinit_smg (void)
1521 int ret;
1523 if (Smg_Inited == 0)
1524 return SLsmg_init_smg ();
1526 BLOCK_SIGNALS;
1527 reset_smg ();
1528 ret = init_smg ();
1529 UNBLOCK_SIGNALS;
1530 return ret;
1533 void SLsmg_reset_smg (void)
1535 if (Smg_Inited == 0)
1536 return;
1538 BLOCK_SIGNALS;
1540 reset_smg ();
1541 (*tt_reset_video)();
1543 UNBLOCK_SIGNALS;
1546 void SLsmg_vprintf (char *fmt, va_list ap)
1548 char buf[1024];
1550 if (Smg_Inited == 0) return;
1552 (void) SLvsnprintf (buf, sizeof (buf), fmt, ap);
1553 SLsmg_write_string (buf);
1556 void SLsmg_printf (char *fmt, ...)
1558 va_list ap;
1559 char *f;
1561 if (Smg_Inited == 0) return;
1563 va_start(ap, fmt);
1565 f = fmt;
1566 while (*f && (*f != '%'))
1567 f++;
1568 if (f != fmt)
1569 SLsmg_write_chars ((SLuchar_Type *)fmt, (SLuchar_Type *)f);
1571 if (*f != 0)
1572 SLsmg_vprintf (f, ap);
1574 va_end (ap);
1577 void SLsmg_set_screen_start (int *r, int *c)
1579 int orow = Start_Row, oc = Start_Col;
1581 if (Smg_Inited == 0) return;
1583 if (c == NULL) Start_Col = 0;
1584 else
1586 Start_Col = *c;
1587 *c = oc;
1589 if (r == NULL) Start_Row = 0;
1590 else
1592 Start_Row = *r;
1593 *r = orow;
1597 void SLsmg_draw_object (int r, int c, SLwchar_Type object)
1599 This_Row = r; This_Col = c;
1601 if (Smg_Inited == 0) return;
1603 if (point_visible (1))
1605 int color = This_Color;
1606 This_Color |= SLSMG_ACS_MASK;
1607 SLsmg_write_char (object);
1608 This_Color = color;
1611 This_Col = c + 1;
1614 void SLsmg_draw_hline (unsigned int n)
1616 static unsigned char hbuf[16];
1617 int cmin, cmax;
1618 int final_col = This_Col + (int) n;
1619 int save_color;
1621 if (Smg_Inited == 0) return;
1623 if ((This_Row < Start_Row) || (This_Row >= Start_Row + (int)Screen_Rows)
1624 || (0 == compute_clip (This_Col, n, Start_Col, Start_Col + (int)Screen_Cols,
1625 &cmin, &cmax)))
1627 This_Col = final_col;
1628 return;
1631 n = (unsigned int)(cmax - cmin);
1633 save_color = This_Color;
1634 This_Color |= SLSMG_ACS_MASK;
1635 This_Col = cmin;
1638 if (hbuf[0] == 0)
1640 SLMEMSET ((char *) hbuf, SLSMG_HLINE_CHAR, 16);
1644 while (n)
1646 SLsmg_write_char (SLSMG_HLINE_CHAR);
1647 n--;
1649 This_Color = save_color;
1650 This_Col = final_col;
1653 void SLsmg_draw_vline (int n)
1655 int c = This_Col, rmin, rmax;
1656 int final_row = This_Row + n;
1657 int save_color;
1659 if (Smg_Inited == 0) return;
1661 if (((c < Start_Col) || (c >= Start_Col + (int)Screen_Cols))
1662 || (0 == compute_clip (This_Row, n, Start_Row,
1663 Start_Row + (int)Screen_Rows,
1664 &rmin, &rmax)))
1666 This_Row = final_row;
1667 return;
1670 save_color = This_Color;
1671 This_Color |= SLSMG_ACS_MASK;
1673 for (This_Row = rmin; This_Row < rmax; This_Row++)
1675 This_Col = c;
1676 SLsmg_write_char (SLSMG_VLINE_CHAR);
1679 This_Col = c; This_Row = final_row;
1680 This_Color = save_color;
1683 void SLsmg_draw_box (int r, int c, unsigned int dr, unsigned int dc)
1685 if (Smg_Inited == 0) return;
1687 if (!dr || !dc) return;
1688 This_Row = r; This_Col = c;
1689 dr--; dc--;
1690 SLsmg_draw_hline (dc);
1691 SLsmg_draw_vline (dr);
1692 This_Row = r; This_Col = c;
1693 SLsmg_draw_vline (dr);
1694 SLsmg_draw_hline (dc);
1695 SLsmg_draw_object (r, c, SLSMG_ULCORN_CHAR);
1696 SLsmg_draw_object (r, c + (int) dc, SLSMG_URCORN_CHAR);
1697 SLsmg_draw_object (r + (int) dr, c, SLSMG_LLCORN_CHAR);
1698 SLsmg_draw_object (r + (int) dr, c + (int) dc, SLSMG_LRCORN_CHAR);
1699 This_Row = r; This_Col = c;
1702 void SLsmg_fill_region (int r, int c, unsigned int dr, unsigned int dc, SLwchar_Type wch)
1704 static unsigned char buf[16];
1705 unsigned char ubuf[16*SLUTF8_MAX_MBLEN];
1706 unsigned char *b, *bmax;
1707 int count;
1708 int dcmax, rmax;
1709 unsigned int wchlen;
1711 if (Smg_Inited == 0) return;
1713 SLsmg_gotorc (r, c);
1714 r = This_Row; c = This_Col;
1716 dcmax = Screen_Cols - This_Col;
1717 if (dcmax < 0)
1718 return;
1720 if (dc > (unsigned int) dcmax) dc = (unsigned int) dcmax;
1722 rmax = This_Row + (int)dr;
1723 if (rmax > (int)Screen_Rows) rmax = (int)Screen_Rows;
1725 if ((wch < 0x80)
1726 || (UTF8_Mode == 0))
1728 if (buf[0] != (unsigned char) wch)
1729 memset ((char *) buf, (unsigned char) wch, sizeof(buf));
1730 b = buf;
1731 bmax = buf + sizeof (buf);
1732 wchlen = 1;
1734 else
1736 unsigned int i;
1738 b = ubuf;
1739 bmax = SLutf8_encode (wch, b, SLUTF8_MAX_MBLEN);
1740 if (bmax == NULL)
1742 bmax = ubuf;
1743 *bmax++ = '?';
1745 wchlen = (unsigned int) (bmax - b);
1746 for (i = 1; i < 16; i++)
1748 memcpy (bmax, b, wchlen);
1749 bmax += wchlen;
1753 for (This_Row = r; This_Row < rmax; This_Row++)
1755 This_Col = c;
1756 count = dc / 16;
1757 SLsmg_write_chars (b, b + wchlen * (dc % 16));
1758 while (count-- > 0)
1760 SLsmg_write_chars (b, bmax);
1764 This_Row = r;
1767 void SLsmg_forward (int n)
1769 This_Col += n;
1772 void
1773 SLsmg_set_color_in_region (int color, int r, int c, unsigned int dr, unsigned int dc)
1775 int cmax, rmax;
1777 if (Smg_Inited == 0) return;
1779 c -= Start_Col;
1780 r -= Start_Row;
1782 cmax = c + (int) dc;
1783 rmax = r + (int) dr;
1785 if (cmax > (int)Screen_Cols) cmax = (int)Screen_Cols;
1786 if (rmax > (int)Screen_Rows) rmax = (int)Screen_Rows;
1788 if (c < 0) c = 0;
1789 if (r < 0) r = 0;
1791 #ifdef REQUIRES_NON_BCE_SUPPORT
1792 if (Bce_Color_Offset)
1793 color += Bce_Color_Offset;
1794 #endif
1796 while (r < rmax)
1798 SLsmg_Char_Type *cell, *cell_max;
1800 SL_Screen[r].flags |= TOUCHED;
1801 cell = SL_Screen[r].neew;
1802 cell_max = cell + cmax;
1803 cell += c;
1805 while (cell < cell_max)
1807 int acs = cell->color & SLSMG_ACS_MASK;
1808 cell->color = color | acs;
1809 cell++;
1811 r++;
1815 void SLsmg_set_terminal_info (SLsmg_Term_Type *tt)
1817 if (tt == NULL) /* use default */
1818 return;
1820 if ((tt->tt_normal_video == NULL)
1821 || (tt->tt_goto_rc == NULL)
1822 || (tt->tt_cls == NULL)
1823 || (tt->tt_del_eol == NULL)
1824 || (tt->tt_smart_puts == NULL)
1825 || (tt->tt_flush_output == NULL)
1826 || (tt->tt_reset_video == NULL)
1827 || (tt->tt_init_video == NULL)
1828 #ifndef IBMPC_SYSTEM
1829 || (tt->tt_set_scroll_region == NULL)
1830 || (tt->tt_reverse_index == NULL)
1831 || (tt->tt_reset_scroll_region == NULL)
1832 || (tt->tt_delete_nlines == NULL)
1833 /* Variables */
1834 || (tt->tt_term_cannot_scroll == NULL)
1835 || (tt->tt_has_alt_charset == NULL)
1836 #if 0 /* These can be NULL */
1837 || (tt->tt_use_blink_for_acs == NULL)
1838 || (tt->tt_graphic_char_pairs == NULL)
1839 #endif
1840 || (tt->tt_screen_cols == NULL)
1841 || (tt->tt_screen_rows == NULL)
1842 #endif
1844 SLang_exit_error ("The Terminal not powerful enough for S-Lang's SLsmg interface");
1846 tt_normal_video = tt->tt_normal_video;
1847 tt_goto_rc = tt->tt_goto_rc;
1848 tt_cls = tt->tt_cls;
1849 tt_del_eol = tt->tt_del_eol;
1850 tt_smart_puts = tt->tt_smart_puts;
1851 tt_flush_output = tt->tt_flush_output;
1852 tt_reset_video = tt->tt_reset_video;
1853 tt_init_video = tt->tt_init_video;
1855 #ifndef IBMPC_SYSTEM
1856 tt_set_scroll_region = tt->tt_set_scroll_region;
1857 tt_reverse_index = tt->tt_reverse_index;
1858 tt_reset_scroll_region = tt->tt_reset_scroll_region;
1859 tt_delete_nlines = tt->tt_delete_nlines;
1861 tt_Term_Cannot_Scroll = tt->tt_term_cannot_scroll;
1862 #endif
1864 tt_Has_Alt_Charset = tt->tt_has_alt_charset;
1865 tt_Screen_Cols = tt->tt_screen_cols;
1866 tt_Screen_Rows = tt->tt_screen_rows;
1867 tt_unicode_ok = tt->unicode_ok;
1870 /* The following routines are partially supported. */
1871 void SLsmg_write_color_chars (SLsmg_Char_Type *s, unsigned int len)
1873 #if 1
1874 SLsmg_write_raw (s, len);
1875 #else
1876 SLsmg_Char_Type *smax, sh;
1877 char buf[32], *b, *bmax;
1878 int color, save_color;
1880 if (Smg_Inited == 0) return;
1882 smax = s + len;
1883 b = buf;
1884 bmax = b + sizeof (buf);
1886 save_color = This_Color;
1888 while (s < smax)
1890 sh = *s++;
1892 color = SLSMG_EXTRACT_COLOR(sh);
1894 #ifdef REQUIRES_NON_BCE_SUPPORT
1895 if (Bce_Color_Offset)
1897 if (color & 0x80)
1898 color = ((color & 0x7F) + Bce_Color_Offset) | 0x80;
1899 else
1900 color = ((color & 0x7F) + Bce_Color_Offset) & 0x7F;
1902 #endif
1904 if ((color != This_Color) || (b == bmax))
1906 if (b != buf)
1908 SLsmg_write_nchars (buf, (int) (b - buf));
1909 b = buf;
1911 This_Color = color;
1913 *b++ = (char) SLSMG_EXTRACT_CHAR(sh);
1916 if (b != buf)
1917 SLsmg_write_nchars (buf, (unsigned int) (b - buf));
1919 This_Color = save_color;
1920 #endif
1923 unsigned int SLsmg_strwidth (SLuchar_Type *u, SLuchar_Type *umax)
1925 unsigned char display_8bit;
1926 int utf8_mode = UTF8_Mode;
1927 int col;
1929 if (u == NULL)
1930 return 0;
1932 display_8bit = (unsigned char) SLsmg_Display_Eight_Bit;
1933 if (utf8_mode)
1934 display_8bit = 0xA0;
1936 col = This_Col;
1938 while (u < umax)
1940 SLuchar_Type ch;
1941 unsigned int nconsumed;
1942 SLwchar_Type wc;
1944 ch = *u;
1945 if (ch < 0x80)
1947 u++;
1949 if ((ch >= 0x20) && (ch != 0x7F))
1951 col++;
1952 continue;
1955 if ((ch == '\t') && (SLsmg_Tab_Width > 0))
1957 if (col >= 0)
1958 col = (1 + col/SLsmg_Tab_Width) * SLsmg_Tab_Width;
1959 else
1960 col = ((col + 1)/SLsmg_Tab_Width) * SLsmg_Tab_Width;
1962 continue;
1965 if ((ch == '\n')
1966 && (SLsmg_Newline_Behavior != SLSMG_NEWLINE_PRINTABLE))
1967 break;
1969 if ((ch == 0x8) && SLsmg_Backspace_Moves)
1971 col--;
1972 continue;
1974 #if SLSMG_HAS_EMBEDDED_ESCAPE
1975 if ((ch == 033) && Embedded_Escape_Mode)
1977 SLsmg_Color_Type color;
1978 if (0 == parse_embedded_escape (u, umax, 0, &u, &color))
1979 continue;
1981 #endif
1982 col += 2;
1983 continue;
1986 nconsumed = 1;
1987 if ((utf8_mode == 0)
1988 || (NULL == SLutf8_decode (u, umax, &wc, &nconsumed)))
1990 if ((utf8_mode == 0)
1991 && (display_8bit && (*u >= display_8bit)))
1992 col++;
1993 else
1994 col += 4*nconsumed;
1995 u += nconsumed;
1996 continue;
1999 u += nconsumed;
2000 if (wc < (SLwchar_Type)display_8bit)
2002 col += 4;
2003 continue;
2005 col += SLwchar_wcwidth (wc);
2008 if (col < This_Col)
2009 return 0;
2011 return (unsigned int) (col - This_Col);
2014 /* If the string u were written at the current positition, this function
2015 * returns the number of bytes necessary to reach the specified width.
2017 unsigned int SLsmg_strbytes (SLuchar_Type *u, SLuchar_Type *umax, unsigned int width)
2019 SLuchar_Type *ustart;
2020 unsigned char display_8bit;
2021 int utf8_mode = UTF8_Mode;
2022 int col, col_max;
2024 if (u == NULL)
2025 return 0;
2027 display_8bit = (unsigned char) SLsmg_Display_Eight_Bit;
2028 if (utf8_mode)
2029 display_8bit = 0xA0;
2031 col = This_Col;
2032 col_max = col + width;
2033 ustart = u;
2035 while (u < umax)
2037 SLuchar_Type ch;
2038 SLwchar_Type wc;
2039 unsigned int nconsumed = 1;
2041 ch = *u;
2042 if (ch < 0x80)
2044 if ((ch >= 0x20) && (ch != 0x7F))
2045 col++;
2046 else if ((ch == '\t') && (SLsmg_Tab_Width > 0))
2048 if (col >= 0)
2049 col = (1 + col/SLsmg_Tab_Width) * SLsmg_Tab_Width;
2050 else
2051 col = ((col + 1)/SLsmg_Tab_Width) * SLsmg_Tab_Width;
2053 else if ((ch == '\n')
2054 && (SLsmg_Newline_Behavior != SLSMG_NEWLINE_PRINTABLE))
2055 break;
2056 else if ((ch == 0x8) && SLsmg_Backspace_Moves)
2057 col--;
2058 #if SLSMG_HAS_EMBEDDED_ESCAPE
2059 else if ((ch == 033) && Embedded_Escape_Mode)
2061 SLsmg_Color_Type color;
2062 SLuchar_Type *u1 = u+1;
2063 if (-1 == parse_embedded_escape (u1, umax, 0, &u1, &color))
2064 col += 2;
2065 nconsumed = (u1 - u);
2067 #endif
2068 else col += 2;
2070 else if ((utf8_mode == 0)
2071 || (NULL == SLutf8_decode (u, umax, &wc, &nconsumed)))
2073 if ((utf8_mode == 0)
2074 && (display_8bit && (*u >= display_8bit)))
2075 col++;
2076 else
2077 col += 4*nconsumed; /* <XX> */
2079 else if (wc < (SLwchar_Type)display_8bit)
2080 col += 4;
2081 else col += SLwchar_wcwidth (wc);
2083 if (col >= col_max)
2084 break;
2086 u += nconsumed;
2089 return (unsigned int) (u - ustart);
2092 unsigned int SLsmg_read_raw (SLsmg_Char_Type *buf, unsigned int len)
2094 unsigned int r, c;
2096 if (Smg_Inited == 0) return 0;
2098 if (0 == point_visible (1)) return 0;
2100 r = (unsigned int) (This_Row - Start_Row);
2101 c = (unsigned int) (This_Col - Start_Col);
2103 if (c + len > (unsigned int) Screen_Cols)
2104 len = (unsigned int) Screen_Cols - c;
2106 memcpy ((char *) buf, (char *) (SL_Screen[r].neew + c), len * sizeof (SLsmg_Char_Type));
2107 return len;
2110 unsigned int SLsmg_write_raw (SLsmg_Char_Type *buf, unsigned int len)
2112 unsigned int r, c;
2113 SLsmg_Char_Type *dest;
2115 if (Smg_Inited == 0) return 0;
2117 if (0 == point_visible (1)) return 0;
2119 r = (unsigned int) (This_Row - Start_Row);
2120 c = (unsigned int) (This_Col - Start_Col);
2122 if (c + len > (unsigned int) Screen_Cols)
2123 len = (unsigned int) Screen_Cols - c;
2125 dest = SL_Screen[r].neew + c;
2127 if (0 != memcmp ((char *) dest, (char *) buf, len * sizeof (SLsmg_Char_Type)))
2129 memcpy ((char *) dest, (char *) buf, len * sizeof (SLsmg_Char_Type));
2130 SL_Screen[r].flags |= TOUCHED;
2132 return len;
2135 int SLsmg_char_at (SLsmg_Char_Type *cp)
2137 if (Smg_Inited == 0) return -1;
2139 if (point_visible (1))
2141 SLsmg_Char_Type *c = &SL_Screen[This_Row - Start_Row].neew[This_Col - Start_Col];
2142 if (c->nchars == 0)
2143 return -1;
2144 *cp = *c;
2145 return 0;
2147 return -1;
2150 int SLsmg_utf8_enable (int mode)
2152 if (mode == -1)
2153 mode = _pSLutf8_mode;
2155 return UTF8_Mode = mode;
2158 int SLsmg_is_utf8_mode (void)
2160 int mode = UTF8_Mode;
2161 if (mode == -1)
2162 mode = _pSLutf8_mode;
2164 return mode;