root/lib/tty/tty-slang.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. tty_setup_sigwinch
  2. sigwinch_handler
  3. slang_reset_softkeys
  4. do_define_key
  5. load_terminfo_keys
  6. mc_tty_normalize_lines_char
  7. tty_init
  8. tty_shutdown
  9. tty_enter_ca_mode
  10. tty_exit_ca_mode
  11. tty_change_screen_size
  12. tty_reset_prog_mode
  13. tty_reset_shell_mode
  14. tty_raw_mode
  15. tty_noraw_mode
  16. tty_noecho
  17. tty_flush_input
  18. tty_keypad
  19. tty_nodelay
  20. tty_baudrate
  21. tty_lowlevel_getch
  22. tty_reset_screen
  23. tty_touch_screen
  24. tty_gotoyx
  25. tty_getyx
  26. tty_draw_hline
  27. tty_draw_vline
  28. tty_fill_region
  29. tty_colorize_area
  30. tty_set_alt_charset
  31. tty_display_8bit
  32. tty_print_char
  33. tty_print_alt_char
  34. tty_print_anychar
  35. tty_print_string
  36. tty_printf
  37. tty_tgetstr
  38. tty_refresh
  39. tty_beep

   1 /*
   2    Interface to the terminal controlling library.
   3    Slang wrapper.
   4 
   5    Copyright (C) 2005-2025
   6    Free Software Foundation, Inc.
   7 
   8    Written by:
   9    Andrew Borodin <aborodin@vmail.ru>, 2009
  10    Egmont Koblinger <egmont@gmail.com>, 2010
  11 
  12    This file is part of the Midnight Commander.
  13 
  14    The Midnight Commander is free software: you can redistribute it
  15    and/or modify it under the terms of the GNU General Public License as
  16    published by the Free Software Foundation, either version 3 of the License,
  17    or (at your option) any later version.
  18 
  19    The Midnight Commander is distributed in the hope that it will be useful,
  20    but WITHOUT ANY WARRANTY; without even the implied warranty of
  21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22    GNU General Public License for more details.
  23 
  24    You should have received a copy of the GNU General Public License
  25    along with this program.  If not, see <https://www.gnu.org/licenses/>.
  26  */
  27 
  28 /** \file
  29  *  \brief Source: S-Lang-based tty layer of Midnight Commander
  30  */
  31 
  32 #include <config.h>
  33 
  34 #include <stdio.h>
  35 #include <stdlib.h>
  36 #include <string.h>
  37 #include <sys/types.h>  // size_t
  38 #include <unistd.h>
  39 #ifdef HAVE_SYS_IOCTL_H
  40 #    include <sys/ioctl.h>
  41 #endif
  42 #include <termios.h>
  43 
  44 #include "lib/global.h"
  45 #include "lib/strutil.h"  // str_term_form
  46 #include "lib/util.h"     // is_printable()
  47 
  48 #include "tty-internal.h"  // mc_tty_normalize_from_utf8()
  49 #include "tty.h"
  50 #include "color.h"
  51 #include "color-slang.h"
  52 #include "color-internal.h"
  53 #include "mouse.h"  // Gpm_Event is required in key.h
  54 #include "key.h"    // define_sequence
  55 #include "win.h"
  56 
  57 /*** global variables ****************************************************************************/
  58 
  59 /* If true program softkeys (HP terminals only) on startup and after every
  60    command ran in the subshell to the description found in the termcap/terminfo
  61    database */
  62 int reset_hp_softkeys = 0;
  63 
  64 /*** file scope macro definitions ****************************************************************/
  65 
  66 #ifndef SLTT_MAX_SCREEN_COLS
  67 #    define SLTT_MAX_SCREEN_COLS 512
  68 #endif
  69 
  70 #ifndef SLTT_MAX_SCREEN_ROWS
  71 #    define SLTT_MAX_SCREEN_ROWS 512
  72 #endif
  73 
  74 /*** file scope type declarations ****************************************************************/
  75 
  76 /*** forward declarations (file scope functions) *************************************************/
  77 
  78 /*** file scope variables ************************************************************************/
  79 
  80 /* Various saved termios settings that we control here */
  81 static struct termios boot_mode;
  82 static struct termios new_mode;
  83 
  84 /* Controls whether we should wait for input in tty_lowlevel_getch */
  85 static gboolean no_slang_delay;
  86 
  87 static gboolean slsmg_active = FALSE;
  88 
  89 /* This table describes which capabilities we want and which values we
  90  * assign to them.
  91  */
  92 static const struct
  93 {
  94     int key_code;
  95     const char *key_name;
  96 } key_table[] = {
  97     { KEY_F (0), "k0" },
  98     { KEY_F (1), "k1" },
  99     { KEY_F (2), "k2" },
 100     { KEY_F (3), "k3" },
 101     { KEY_F (4), "k4" },
 102     { KEY_F (5), "k5" },
 103     { KEY_F (6), "k6" },
 104     { KEY_F (7), "k7" },
 105     { KEY_F (8), "k8" },
 106     { KEY_F (9), "k9" },
 107     { KEY_F (10), "k;" },
 108     { KEY_F (11), "F1" },
 109     { KEY_F (12), "F2" },
 110     { KEY_F (13), "F3" },
 111     { KEY_F (14), "F4" },
 112     { KEY_F (15), "F5" },
 113     { KEY_F (16), "F6" },
 114     { KEY_F (17), "F7" },
 115     { KEY_F (18), "F8" },
 116     { KEY_F (19), "F9" },
 117     { KEY_F (20), "FA" },
 118     { KEY_IC, "kI" },
 119     { KEY_NPAGE, "kN" },
 120     { KEY_PPAGE, "kP" },
 121     { KEY_LEFT, "kl" },
 122     { KEY_RIGHT, "kr" },
 123     { KEY_UP, "ku" },
 124     { KEY_DOWN, "kd" },
 125     { KEY_DC, "kD" },
 126     { KEY_BACKSPACE, "kb" },
 127     { KEY_HOME, "kh" },
 128     { KEY_END, "@7" },
 129     {
 130         0,
 131         NULL,
 132     },
 133 };
 134 
 135 /* --------------------------------------------------------------------------------------------- */
 136 /*** file scope functions ************************************************************************/
 137 /* --------------------------------------------------------------------------------------------- */
 138 
 139 static void
 140 tty_setup_sigwinch (void (*handler) (int))
     /* [previous][next][first][last][top][bottom][index][help]  */
 141 {
 142     (void) SLsignal (SIGWINCH, handler);
 143     tty_create_winch_pipe ();
 144 }
 145 
 146 /* --------------------------------------------------------------------------------------------- */
 147 
 148 static void
 149 sigwinch_handler (int dummy)
     /* [previous][next][first][last][top][bottom][index][help]  */
 150 {
 151     ssize_t n = 0;
 152 
 153     (void) dummy;
 154 
 155     n = write (sigwinch_pipe[1], "", 1);
 156     (void) n;
 157 
 158     (void) SLsignal (SIGWINCH, sigwinch_handler);
 159 }
 160 
 161 /* --------------------------------------------------------------------------------------------- */
 162 
 163 /* HP Terminals have capabilities (pfkey, pfloc, pfx) to program function keys.
 164    elm 2.4pl15 invoked with the -K option utilizes these softkeys and the
 165    consequence is that function keys don't work in MC sometimes...
 166    Unfortunately I don't now the one and only escape sequence to turn off.
 167    softkeys (elm uses three different capabilities to turn on softkeys and two.
 168    capabilities to turn them off)..
 169    Among other things elm uses the pair we already use in slang_keypad. That's.
 170    the reason why I call slang_reset_softkeys from slang_keypad. In lack of
 171    something better the softkeys are programmed to their defaults from the
 172    termcap/terminfo database.
 173    The escape sequence to program the softkeys is taken from elm and it is.
 174    hardcoded because neither slang nor ncurses 4.1 know how to 'printf' this.
 175    sequence. -- Norbert
 176  */
 177 
 178 static void
 179 slang_reset_softkeys (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 180 {
 181     int key;
 182     static const char display[] = "                ";
 183     char tmp[BUF_SMALL];
 184 
 185     for (key = 1; key < 9; key++)
 186     {
 187         char *send;
 188 
 189         g_snprintf (tmp, sizeof (tmp), "k%d", key);
 190         send = SLtt_tgetstr (tmp);
 191         if (send != NULL)
 192         {
 193             g_snprintf (tmp, sizeof (tmp), ESC_STR "&f%dk%dd%dL%s%s", key,
 194                         (int) (sizeof (display) - 1), (int) strlen (send), display, send);
 195             SLtt_write_string (tmp);
 196         }
 197     }
 198 }
 199 
 200 /* --------------------------------------------------------------------------------------------- */
 201 
 202 static void
 203 do_define_key (int code, const char *strcap)
     /* [previous][next][first][last][top][bottom][index][help]  */
 204 {
 205     char *seq;
 206 
 207     seq = SLtt_tgetstr ((SLFUTURE_CONST char *) strcap);
 208     if (seq != NULL)
 209         define_sequence (code, seq, MCKEY_NOACTION);
 210 }
 211 
 212 /* --------------------------------------------------------------------------------------------- */
 213 
 214 static void
 215 load_terminfo_keys (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 216 {
 217     int i;
 218 
 219     for (i = 0; key_table[i].key_code; i++)
 220         do_define_key (key_table[i].key_code, key_table[i].key_name);
 221 }
 222 
 223 /* --------------------------------------------------------------------------------------------- */
 224 /*** public functions ****************************************************************************/
 225 /* --------------------------------------------------------------------------------------------- */
 226 
 227 int
 228 mc_tty_normalize_lines_char (const char *str)
     /* [previous][next][first][last][top][bottom][index][help]  */
 229 {
 230     char *str2;
 231     int res;
 232 
 233     struct mc_tty_lines_struct
 234     {
 235         const char *line;
 236         int line_code;
 237     } const lines_codes[] = {
 238         { "\342\224\214", SLSMG_ULCORN_CHAR },
 239         { "\342\224\220", SLSMG_URCORN_CHAR },
 240         { "\342\224\224", SLSMG_LLCORN_CHAR },
 241         { "\342\224\230", SLSMG_LRCORN_CHAR },
 242         { "\342\224\234", SLSMG_LTEE_CHAR },
 243         { "\342\224\244", SLSMG_RTEE_CHAR },
 244         { "\342\224\254", SLSMG_UTEE_CHAR },
 245         { "\342\224\264", SLSMG_DTEE_CHAR },
 246         { "\342\224\200", SLSMG_HLINE_CHAR },
 247         { "\342\224\202", SLSMG_VLINE_CHAR },
 248         { "\342\224\274", SLSMG_PLUS_CHAR },
 249 
 250         { NULL, 0 },
 251     };
 252 
 253     if (!str)
 254         return (int) ' ';
 255 
 256     for (res = 0; lines_codes[res].line; res++)
 257     {
 258         if (strcmp (str, lines_codes[res].line) == 0)
 259             return lines_codes[res].line_code;
 260     }
 261 
 262     str2 = mc_tty_normalize_from_utf8 (str);
 263     res = g_utf8_get_char_validated (str2, -1);
 264 
 265     if (res < 0)
 266         res = (unsigned char) str2[0];
 267     g_free (str2);
 268 
 269     return res;
 270 }
 271 
 272 /* --------------------------------------------------------------------------------------------- */
 273 
 274 void
 275 tty_init (gboolean mouse_enable, gboolean is_xterm)
     /* [previous][next][first][last][top][bottom][index][help]  */
 276 {
 277     SLtt_Ignore_Beep = 1;
 278 
 279     SLutf8_enable (-1);  // has to be called first before any of the other functions.
 280     SLtt_get_terminfo ();
 281     /*
 282      * If the terminal in not in terminfo but begins with a well-known
 283      * string such as "linux" or "xterm" S-Lang will go on, but the
 284      * terminal size and several other variables won't be initialized
 285      * (as of S-Lang 1.4.4). Detect it and abort. Also detect extremely
 286      * small screen dimensions.
 287      */
 288     if ((COLS < 10)
 289         || (LINES < 5)
 290 #if SLANG_VERSION < 20303
 291         /* Beginning from pre2.3.3-8 (55f58798c267d76a1b93d0d916027b71a10ac1ee),
 292            these limitations were eliminated. */
 293         || (COLS > SLTT_MAX_SCREEN_COLS) || (LINES > SLTT_MAX_SCREEN_ROWS)
 294 #endif
 295     )
 296     {
 297         fprintf (stderr,
 298                  _ ("Screen size %dx%d is not supported.\n"
 299                     "Check the TERM environment variable.\n"),
 300                  COLS, LINES);
 301         exit (EXIT_FAILURE);
 302     }
 303 
 304     tcgetattr (fileno (stdin), &boot_mode);
 305     // 255 = ignore abort char; XCTRL('g') for abort char = ^g
 306     SLang_init_tty (XCTRL ('g'), 1, 0);
 307 
 308     if (mc_global.tty.ugly_line_drawing)
 309         SLtt_Has_Alt_Charset = 0;
 310 
 311     tcgetattr (SLang_TT_Read_FD, &new_mode);
 312 
 313     tty_reset_prog_mode ();
 314     load_terminfo_keys ();
 315 
 316     SLtt_Blink_Mode = (tty_use_256colors (NULL) || tty_use_truecolors (NULL)) ? 1 : 0;
 317 
 318     tty_start_interrupt_key ();
 319 
 320     // It's the small part from the previous init_key()
 321     init_key_input_fd ();
 322 
 323     /* For 8-bit locales, NCurses handles 154 (0x9A) symbol properly, while S-Lang
 324      * requires SLsmg_Display_Eight_Bit >= 154 (OR manual filtering if xterm display
 325      * detected - but checking TERM would fail under screen, OR running xterm
 326      * with allowC1Printable).
 327      */
 328     tty_display_8bit (FALSE);
 329 
 330     SLsmg_init_smg ();
 331     slsmg_active = TRUE;
 332     if (!mouse_enable)
 333         use_mouse_p = MOUSE_DISABLED;
 334     tty_init_xterm_support (is_xterm);  // do it before tty_enter_ca_mode() call
 335     tty_enter_ca_mode ();
 336     tty_keypad (TRUE);
 337     tty_nodelay (FALSE);
 338 
 339     tty_setup_sigwinch (sigwinch_handler);
 340 }
 341 
 342 /* --------------------------------------------------------------------------------------------- */
 343 
 344 void
 345 tty_shutdown (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 346 {
 347     char *op_cap;
 348 
 349     tty_destroy_winch_pipe ();
 350     tty_reset_shell_mode ();
 351     tty_noraw_mode ();
 352     tty_keypad (FALSE);
 353     tty_reset_screen ();
 354     tty_exit_ca_mode ();
 355     SLang_reset_tty ();
 356     slsmg_active = FALSE;
 357 
 358     /* Load the op capability to reset the colors to those that were
 359      * active when the program was started up
 360      */
 361     op_cap = SLtt_tgetstr ((SLFUTURE_CONST char *) "op");
 362     if (op_cap != NULL)
 363     {
 364         fputs (op_cap, stdout);
 365         fflush (stdout);
 366     }
 367 }
 368 
 369 /* --------------------------------------------------------------------------------------------- */
 370 
 371 void
 372 tty_enter_ca_mode (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 373 {
 374     // S-Lang handles alternate screen switching and cursor position saving
 375 }
 376 
 377 /* --------------------------------------------------------------------------------------------- */
 378 
 379 void
 380 tty_exit_ca_mode (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 381 {
 382     // S-Lang handles alternate screen switching and cursor position restoring
 383 }
 384 
 385 /* --------------------------------------------------------------------------------------------- */
 386 
 387 void
 388 tty_change_screen_size (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 389 {
 390     SLtt_get_screen_size ();
 391     if (slsmg_active)
 392         SLsmg_reinit_smg ();
 393 
 394 #ifdef ENABLE_SUBSHELL
 395     if (mc_global.tty.use_subshell)
 396         tty_resize (mc_global.tty.subshell_pty);
 397 #endif
 398 }
 399 
 400 /* --------------------------------------------------------------------------------------------- */
 401 /* Done each time we come back from done mode */
 402 
 403 void
 404 tty_reset_prog_mode (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 405 {
 406     tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
 407     SLsmg_init_smg ();
 408     slsmg_active = TRUE;
 409     SLsmg_touch_lines (0, LINES);
 410 }
 411 
 412 /* --------------------------------------------------------------------------------------------- */
 413 /* Called each time we want to shutdown slang screen manager */
 414 
 415 void
 416 tty_reset_shell_mode (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 417 {
 418     tcsetattr (SLang_TT_Read_FD, TCSANOW, &boot_mode);
 419 }
 420 
 421 /* --------------------------------------------------------------------------------------------- */
 422 
 423 void
 424 tty_raw_mode (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 425 {
 426     tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
 427 }
 428 
 429 /* --------------------------------------------------------------------------------------------- */
 430 
 431 void
 432 tty_noraw_mode (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 433 {
 434 }
 435 
 436 /* --------------------------------------------------------------------------------------------- */
 437 
 438 void
 439 tty_noecho (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 440 {
 441 }
 442 
 443 /* --------------------------------------------------------------------------------------------- */
 444 
 445 int
 446 tty_flush_input (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 447 {
 448     return 0;  // OK
 449 }
 450 
 451 /* --------------------------------------------------------------------------------------------- */
 452 
 453 void
 454 tty_keypad (gboolean set)
     /* [previous][next][first][last][top][bottom][index][help]  */
 455 {
 456     char *keypad_string;
 457 
 458     keypad_string = SLtt_tgetstr ((SLFUTURE_CONST char *) (set ? "ks" : "ke"));
 459     if (keypad_string != NULL)
 460         SLtt_write_string (keypad_string);
 461     if (set && reset_hp_softkeys)
 462         slang_reset_softkeys ();
 463 }
 464 
 465 /* --------------------------------------------------------------------------------------------- */
 466 
 467 void
 468 tty_nodelay (gboolean set)
     /* [previous][next][first][last][top][bottom][index][help]  */
 469 {
 470     no_slang_delay = set;
 471 }
 472 
 473 /* --------------------------------------------------------------------------------------------- */
 474 
 475 int
 476 tty_baudrate (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 477 {
 478     return SLang_TT_Baud_Rate;
 479 }
 480 
 481 /* --------------------------------------------------------------------------------------------- */
 482 
 483 int
 484 tty_lowlevel_getch (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 485 {
 486     int c;
 487 
 488     if (no_slang_delay && (SLang_input_pending (0) == 0))
 489         return -1;
 490 
 491     c = SLang_getkey ();
 492     if (c == SLANG_GETKEY_ERROR)
 493     {
 494         fprintf (stderr,
 495                  "SLang_getkey returned SLANG_GETKEY_ERROR\n"
 496                  "Assuming EOF on stdin and exiting\n");
 497         exit (EXIT_FAILURE);
 498     }
 499 
 500     return c;
 501 }
 502 
 503 /* --------------------------------------------------------------------------------------------- */
 504 
 505 int
 506 tty_reset_screen (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 507 {
 508     SLsmg_reset_smg ();
 509     slsmg_active = FALSE;
 510     return 0;  // OK
 511 }
 512 
 513 /* --------------------------------------------------------------------------------------------- */
 514 
 515 void
 516 tty_touch_screen (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 517 {
 518     SLsmg_touch_lines (0, LINES);
 519 }
 520 
 521 /* --------------------------------------------------------------------------------------------- */
 522 
 523 void
 524 tty_gotoyx (int y, int x)
     /* [previous][next][first][last][top][bottom][index][help]  */
 525 {
 526     SLsmg_gotorc (y, x);
 527 }
 528 
 529 /* --------------------------------------------------------------------------------------------- */
 530 
 531 void
 532 tty_getyx (int *py, int *px)
     /* [previous][next][first][last][top][bottom][index][help]  */
 533 {
 534     *py = SLsmg_get_row ();
 535     *px = SLsmg_get_column ();
 536 }
 537 
 538 /* --------------------------------------------------------------------------------------------- */
 539 
 540 void
 541 tty_draw_hline (int y, int x, int ch, int len)
     /* [previous][next][first][last][top][bottom][index][help]  */
 542 {
 543     int x1;
 544 
 545     if (y < 0 || y >= LINES || x >= COLS)
 546         return;
 547 
 548     x1 = x;
 549 
 550     if (x < 0)
 551     {
 552         len += x;
 553         if (len <= 0)
 554             return;
 555         x = 0;
 556     }
 557 
 558     if (ch == ACS_HLINE)
 559         ch = mc_tty_frm[MC_TTY_FRM_HORIZ];
 560     if (ch == 0)
 561         ch = ACS_HLINE;
 562 
 563     SLsmg_gotorc (y, x);
 564 
 565     if (ch == ACS_HLINE)
 566         SLsmg_draw_hline (len);
 567     else
 568         while (len-- != 0)
 569             tty_print_char (ch);
 570 
 571     SLsmg_gotorc (y, x1);
 572 }
 573 
 574 /* --------------------------------------------------------------------------------------------- */
 575 
 576 void
 577 tty_draw_vline (int y, int x, int ch, int len)
     /* [previous][next][first][last][top][bottom][index][help]  */
 578 {
 579     int y1;
 580 
 581     if (x < 0 || x >= COLS || y >= LINES)
 582         return;
 583 
 584     y1 = y;
 585 
 586     if (y < 0)
 587     {
 588         len += y;
 589         if (len <= 0)
 590             return;
 591         y = 0;
 592     }
 593 
 594     if (ch == ACS_VLINE)
 595         ch = mc_tty_frm[MC_TTY_FRM_VERT];
 596     if (ch == 0)
 597         ch = ACS_VLINE;
 598 
 599     SLsmg_gotorc (y, x);
 600 
 601     if (ch == ACS_VLINE)
 602         SLsmg_draw_vline (len);
 603     else
 604     {
 605         int pos = 0;
 606 
 607         while (len-- != 0)
 608         {
 609             SLsmg_gotorc (y + pos, x);
 610             tty_print_char (ch);
 611             pos++;
 612         }
 613     }
 614 
 615     SLsmg_gotorc (y1, x);
 616 }
 617 
 618 /* --------------------------------------------------------------------------------------------- */
 619 
 620 void
 621 tty_fill_region (int y, int x, int rows, int cols, unsigned char ch)
     /* [previous][next][first][last][top][bottom][index][help]  */
 622 {
 623     SLsmg_fill_region (y, x, rows, cols, ch);
 624 }
 625 
 626 /* --------------------------------------------------------------------------------------------- */
 627 
 628 void
 629 tty_colorize_area (int y, int x, int rows, int cols, int color)
     /* [previous][next][first][last][top][bottom][index][help]  */
 630 {
 631     if (use_colors)
 632         SLsmg_set_color_in_region (color, y, x, rows, cols);
 633 }
 634 
 635 /* --------------------------------------------------------------------------------------------- */
 636 
 637 void
 638 tty_set_alt_charset (gboolean alt_charset)
     /* [previous][next][first][last][top][bottom][index][help]  */
 639 {
 640     SLsmg_set_char_set ((int) alt_charset);
 641 }
 642 
 643 /* --------------------------------------------------------------------------------------------- */
 644 
 645 void
 646 tty_display_8bit (gboolean what)
     /* [previous][next][first][last][top][bottom][index][help]  */
 647 {
 648     SLsmg_Display_Eight_Bit = what ? 128 : 160;
 649 }
 650 
 651 /* --------------------------------------------------------------------------------------------- */
 652 
 653 void
 654 tty_print_char (int c)
     /* [previous][next][first][last][top][bottom][index][help]  */
 655 {
 656     SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
 657 }
 658 
 659 /* --------------------------------------------------------------------------------------------- */
 660 
 661 void
 662 tty_print_alt_char (int c, gboolean single)
     /* [previous][next][first][last][top][bottom][index][help]  */
 663 {
 664 #define DRAW(x, y)                                                                                 \
 665     (x == y) ? SLsmg_draw_object (SLsmg_get_row (), SLsmg_get_column (), x)                        \
 666              : SLsmg_write_char ((unsigned int) y)
 667     switch (c)
 668     {
 669     case ACS_VLINE:
 670         DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_VERT : MC_TTY_FRM_DVERT]);
 671         break;
 672     case ACS_HLINE:
 673         DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_HORIZ : MC_TTY_FRM_DHORIZ]);
 674         break;
 675     case ACS_LTEE:
 676         DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTMIDDLE : MC_TTY_FRM_DLEFTMIDDLE]);
 677         break;
 678     case ACS_RTEE:
 679         DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTMIDDLE : MC_TTY_FRM_DRIGHTMIDDLE]);
 680         break;
 681     case ACS_TTEE:
 682         DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_TOPMIDDLE : MC_TTY_FRM_DTOPMIDDLE]);
 683         break;
 684     case ACS_BTEE:
 685         DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_BOTTOMMIDDLE : MC_TTY_FRM_DBOTTOMMIDDLE]);
 686         break;
 687     case ACS_ULCORNER:
 688         DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTTOP : MC_TTY_FRM_DLEFTTOP]);
 689         break;
 690     case ACS_LLCORNER:
 691         DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_LEFTBOTTOM : MC_TTY_FRM_DLEFTBOTTOM]);
 692         break;
 693     case ACS_URCORNER:
 694         DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTTOP : MC_TTY_FRM_DRIGHTTOP]);
 695         break;
 696     case ACS_LRCORNER:
 697         DRAW (c, mc_tty_frm[single ? MC_TTY_FRM_RIGHTBOTTOM : MC_TTY_FRM_DRIGHTBOTTOM]);
 698         break;
 699     case ACS_PLUS:
 700         DRAW (c, mc_tty_frm[MC_TTY_FRM_CROSS]);
 701         break;
 702     default:
 703         SLsmg_write_char ((unsigned int) c);
 704     }
 705 #undef DRAW
 706 }
 707 
 708 /* --------------------------------------------------------------------------------------------- */
 709 
 710 void
 711 tty_print_anychar (int c)
     /* [previous][next][first][last][top][bottom][index][help]  */
 712 {
 713     if (c > 255)
 714     {
 715         char str[UTF8_CHAR_LEN + 1];
 716         int res;
 717 
 718         res = g_unichar_to_utf8 (c, str);
 719         if (res == 0)
 720         {
 721             str[0] = '.';
 722             str[1] = '\0';
 723         }
 724         else
 725         {
 726             str[res] = '\0';
 727         }
 728         SLsmg_write_string ((char *) str_term_form (str));
 729     }
 730     else
 731     {
 732         if (!is_printable (c))
 733             c = '.';
 734         SLsmg_write_char ((SLwchar_Type) ((unsigned int) c));
 735     }
 736 }
 737 
 738 /* --------------------------------------------------------------------------------------------- */
 739 
 740 void
 741 tty_print_string (const char *s)
     /* [previous][next][first][last][top][bottom][index][help]  */
 742 {
 743     SLsmg_write_string ((char *) str_term_form (s));
 744 }
 745 
 746 /* --------------------------------------------------------------------------------------------- */
 747 
 748 void
 749 tty_printf (const char *fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help]  */
 750 {
 751     va_list args;
 752 
 753     va_start (args, fmt);
 754     SLsmg_vprintf ((char *) fmt, args);
 755     va_end (args);
 756 }
 757 
 758 /* --------------------------------------------------------------------------------------------- */
 759 
 760 char *
 761 tty_tgetstr (const char *cap)
     /* [previous][next][first][last][top][bottom][index][help]  */
 762 {
 763     return SLtt_tgetstr ((SLFUTURE_CONST char *) cap);
 764 }
 765 
 766 /* --------------------------------------------------------------------------------------------- */
 767 
 768 void
 769 tty_refresh (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 770 {
 771     SLsmg_refresh ();
 772 }
 773 
 774 /* --------------------------------------------------------------------------------------------- */
 775 
 776 void
 777 tty_beep (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 778 {
 779     SLtt_beep ();
 780 }
 781 
 782 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */