/* we_term.c                                              */
/* Copyright (C) 1993 Fred Kruse                          */
/* Copyright (C) 2026 Juan Manuel Mendez Rey              */
/* This is free software; you can redistribute it and or  */
/* modify it under the terms of the                       */
/* GNU General Public License, see the file COPYING.      */

#include "edit.h"
#ifdef UNIX

#include <termios.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <poll.h>
#include "we_fdloop.h"

#include<signal.h>
#define KEYFN 42
#define NSPCHR 13

#ifndef XWPE_DLL
#define WpeDllInit WpeTermInit
#endif

/*    we_term.c    */
char *init_key(char *key);
char *init_kkey(char *key);
int init_cursor(void);
int e_begscr(void);
void e_endwin(void);
int fk_t_cursor(int x);
int fk_t_putchar(int c);
int fk_attrset(int a);
int e_t_refresh(void);
int e_t_sys_ini(void);
int e_t_sys_end(void);
int e_t_getch(void);
int e_find_key(int c, int j, int sw);
void e_exitm(char *s, int n);
int fk_t_locate(int x, int y);
int fk_t_mouse(int *g);
static int e_t_mouse_decode_button(mmask_t bstate);
static int e_t_mouse_is_released(mmask_t bstate);
int g_mouse_buttons = 0;
int e_t_initscr(void);
int e_t_kbhit(void);
int e_t_d_switch_out(int sw);
int e_t_switch_screen(int sw);
int e_t_deb_out(FENSTER *f);
int e_s_sys_end();
int e_s_sys_ini();

extern int MAXSLNS;
extern int MAXSCOL;


#ifndef NCURSES
char *key_f[KEYFN], *key_key;
#endif
char *cur_rc, *cur_vs, *cur_nvs, *cur_vvs, cur_attr;
char *att_so, *att_ul, *att_rv, *att_bl, *att_dm, *att_bo;
char *ratt_no, *ratt_so, *ratt_ul, *ratt_rv, *ratt_bl, *ratt_dm, *ratt_bo;
char *beg_scr, *swt_scr, *sav_cur, *res_cur; 
extern SCREENCELL *altschirm;
extern char *att_no;
char *col_fg, *col_bg, *spc_st, *spc_in, *spc_bg, *spc_nd;

extern int col_num;
#ifdef NCURSES
chtype sp_chr[NSPCHR];
#else
char *sp_chr[NSPCHR];
#endif

extern int cur_x, cur_y;
extern struct termios otermio, ntermio, ttermio;
#ifdef TERMCAP
char area[315];
char *ap = area;
char tcbuf[1024];
char *tc_screen;
char *tgetstr();
int tgetnum();
char *tgoto();
#define tigetstr(k) tgetstr(k, &ap)

#define term_move(x,y) e_putp(tgoto(cur_rc, x, y))
#define term_refresh() fflush(stdout)
#else
/* Because term.h defines "buttons" it messes up we_gpm.c if in edit.h */
#include <term.h>

/* AIX requires that tparm has 10 arguments. */
#define tparm1(a,b) tparm((a), (b), 0, 0, 0, 0, 0, 0, 0, 0)
#define tparm2(a,b,c) tparm((a), (b), (c), 0, 0, 0, 0, 0, 0, 0)

#ifdef NCURSES
#define term_move(x,y) move(y, x)
#define term_refresh() refresh()
#else
#define term_move(x,y) e_putp(tparm2(cur_rc, y, x))
#define term_refresh() fflush(stdout)
#endif
#endif

int WpeGpmMouseInit(void);

int WpeDllInit(int *argc, char **argv)
{
 fk_u_cursor = fk_t_cursor;
 fk_u_locate = fk_t_locate;
 e_u_d_switch_out = e_t_d_switch_out;
 e_u_switch_screen = e_t_switch_screen;
 e_u_deb_out = e_t_deb_out;
 e_u_kbhit = e_t_kbhit;
 e_u_s_sys_end = e_s_sys_end;
 e_u_s_sys_ini = e_s_sys_ini;
 e_u_refresh = e_t_refresh;
 e_u_getch = e_t_getch;
 e_u_sys_ini = e_t_sys_ini;
 e_u_sys_end = e_t_sys_end;
 e_u_system = system;
 fk_u_putchar = fk_t_putchar;
#ifdef HAVE_LIBGPM
 if (WpeGpmMouseInit() == 0)
 {
  fk_mouse = WpeGpmMouse;
 }
 else
#endif
  fk_mouse = fk_t_mouse;
 WpeMouseChangeShape = (void (*)(WpeMouseShape))WpeNullFunction;
 WpeMouseRestoreShape = WpeNullFunction;
 WpeDisplayEnd = e_endwin;
#ifdef __linux__
 u_bioskey = WpeLinuxBioskey;
#else
 u_bioskey = WpeZeroFunction;
#endif
 e_t_initscr();
 if (col_num > 0)
 {
  e_pr_u_col_kasten = e_pr_x_col_kasten;
  e_frb_u_menue = e_frb_x_menue;
  e_s_u_clr = e_s_x_clr;
  e_n_u_clr = e_n_x_clr;
 }
 else
 {
  e_pr_u_col_kasten = e_pr_t_col_kasten;
  e_frb_u_menue = e_frb_t_menue;
  e_s_u_clr = e_s_t_clr;
  e_n_u_clr = e_n_t_clr;
 }
 MCI = 7;
 MCA = 11;
 RD1 = '\01';
 RD2 = '\02';
 RD3 = '\03';
 RD4 = '\04';
 RD5 = '\05';
 RD6 = '\06';
 RE1 = '\01';
 RE2 = '\02';
 RE3 = '\03';
 RE4 = '\04';
 RE5 = '\05';
 RE6 = '\06';
 WBT = '\13';
 ctree[0] = "\11\12\07";   /*  07 -> 30  */
 ctree[1] = "\11\12\12";	/*  11 -> 16  */
 ctree[2] = "\11\07\12";   /*  12 -> 22  */
 ctree[3] = "\10\12\12";   /*  10 -> 25  */
 ctree[4] = "\11\12\12";
/*
 RD1 = '+';
 RD2 = '+';
 RD3 = '+';
 RD4 = '+';
 RD5 = '-';
 RD6 = '|';
*//*
 RE1 = '.';
 RE2 = '.';
 RE3 = '.';
 RE4 = '.';
 RE5 = '.';
 RE6 = ':';
 WBT = '#';
 ctree[0] = "|__";
 ctree[1] = "|__";
 ctree[2] = "|__";
 ctree[3] = "|__";
 ctree[4] = "|__";
*/
 return 0;
}

char *init_key(char *key)
{
 char *tmp, *keystr;

 tmp = (char *) tigetstr(key);
 if (tmp == NULL || tmp == ((char *) -1))
  return(NULL);
 else
 {
  keystr = MALLOC(strlen(tmp)+1);
  strcpy(keystr, tmp);
 }
 return(keystr);
}

#ifndef NCURSES
char *init_kkey(char *key)
{
 char *tmp;
 int i;

 tmp = init_key(key);
 if (tmp == NULL)
  return(NULL);
 if (!key_key)
 {
  key_key = MALLOC(2);
  key_key[0] = tmp[1];
  key_key[1] = '\0';
  return(tmp);
 }
 else
 {
  for (i = 0; key_key[i] != '\0'; i++)
   if (key_key[i] == tmp[1])
    return(tmp);
  key_key = REALLOC(key_key, i + 2);
  key_key[i] = tmp[1];
  key_key[i + 1] = '\0';
 }
 return(tmp);
}
#endif

char *init_spchr(char c)
{
 int i;
 char *pt = NULL;

 if (!spc_st || !spc_bg || !spc_nd)
  return(NULL);
 for (i = 0; spc_st[i] && spc_st[i+1] && spc_st[i] != c; i+=2)
  ;
 if (spc_st[i] && spc_st[i+1])
 {
  pt = MALLOC((strlen(spc_bg)+strlen(spc_nd)+2)*sizeof(char));
  if(pt)
   sprintf(pt, "%s%c%s", spc_bg, spc_st[i+1], spc_nd);
 }
 return(pt);
}

int init_cursor()
{
#ifndef TERMCAP
   if (!(cur_rc = init_key("cup")))
    return(-1);
   if ((col_fg = init_key("setaf")) && (col_bg = init_key("setab")))
   { /* terminfo 10.2.x color code */
    if ((col_num = tigetnum("colors")) < 0) col_num = 8;
   }
   else if ((col_fg = init_key("setf")) && (col_bg = init_key("setb")))
   { /* Older terminfo color code */
    if((col_num = tigetnum("colors")) < 0) col_num = 8;
   }
   else
   { /* No colors */
    if(col_fg) {  free(col_fg);  col_fg = NULL;   }
    if(col_bg) {  free(col_bg);  col_bg = NULL;   }
   }

   spc_st = init_key("acsc");
   spc_in = init_key("enacs");
   spc_bg = init_key("smacs");
   spc_nd = init_key("rmacs");
   att_no = init_key("sgr0");
   att_so = init_key("smso");
   att_ul = init_key("smul");
   att_rv = init_key("rev");
   att_bl = init_key("blink");
   att_dm = init_key("dim");
   att_bo = init_key("bold");
   ratt_no = init_key("sgr0");
   ratt_so = init_key("rmso");
   ratt_ul = init_key("rmul");
   ratt_rv = init_key("sgr0");
   ratt_bl = init_key("sgr0");
   ratt_dm = init_key("sgr0");
   ratt_bo = init_key("sgr0");
   beg_scr = init_key("smcup");
   swt_scr = init_key("rmcup");
   sav_cur = init_key("sc");
   res_cur = init_key("rc");

#ifndef NCURSES
   key_f[0] = init_kkey("kf1");
   key_f[1] = init_kkey("kf2");
   key_f[2] = init_kkey("kf3");
   key_f[3] = init_kkey("kf4");
   key_f[4] = init_kkey("kf5");
   key_f[5] = init_kkey("kf6");
   key_f[6] = init_kkey("kf7");
   key_f[7] = init_kkey("kf8");
   key_f[8] = init_kkey("kf9");
   key_f[9] = init_kkey("kf10");
   key_f[10] = init_kkey("kcuu1");
   key_f[11] = init_kkey("kcud1");
   key_f[12] = init_kkey("kcub1");
   key_f[13] = init_kkey("kcuf1");
   key_f[14] = init_kkey("kich1");
   key_f[15] = init_kkey("khome");
   key_f[16] = init_kkey("kpp");
   if(!(key_f[17] = init_kkey("kdch1"))) key_f[17] = "\177";
   key_f[18] = init_kkey("kend");
   key_f[19] = init_kkey("knp");
   key_f[20] = init_kkey("kbs");
   key_f[21] = init_kkey("khlp");
   key_f[22] = init_kkey("kll");
   key_f[23] = init_kkey("kf17");
   key_f[24] = init_kkey("kf18");
   key_f[25] = init_kkey("kf19");
   key_f[26] = init_kkey("kf20");
   key_f[27] = init_kkey("kf21");
   key_f[28] = init_kkey("kf22");
   key_f[29] = init_kkey("kf23");
   key_f[30] = init_kkey("kf24");
   key_f[31] = init_kkey("kf25");
   key_f[32] = init_kkey("kf26");
   key_f[33] = init_kkey("kPRV");
   key_f[34] = init_kkey("kNXT");
   key_f[35] = init_kkey("kLFT");
   key_f[36] = init_kkey("kRIT");
   key_f[37] = init_kkey("kHOM");
   key_f[38] = init_kkey("kri");
   key_f[39] = init_kkey("kEND");
   key_f[40] = init_kkey("kind");
   key_f[41] = init_kkey("kext");
#endif

#else

   if(!(cur_rc = init_key("cm"))) return(-1);
   if((col_fg = init_key("Sf")) && (col_bg = init_key("Sb")))
   {  if((col_num = tgetnum("Co")) < 0) col_num = 8;  }
   else
   {  if(col_fg) {  free(col_fg);  col_fg = NULL;   }
      if(col_bg) {  free(col_bg);  col_bg = NULL;   }
   }
   spc_st = init_key("ac");
   spc_in = init_key("eA");
   spc_bg = init_key("as");
   spc_nd = init_key("ae");
   att_no = init_key("me");
   att_so = init_key("so");
   att_ul = init_key("us");
   att_rv = init_key("mr");
   att_bl = init_key("mb");
   att_dm = init_key("mh");
   att_bo = init_key("md");
   ratt_no = init_key("me");
   ratt_so = init_key("se");
   ratt_ul = init_key("ue");
   ratt_rv = init_key("me");
   ratt_bl = init_key("me");
   ratt_dm = init_key("me");
   ratt_bo = init_key("me");
   beg_scr = init_key("ti");
   swt_scr = init_key("te");
   sav_cur = init_key("sc");
   res_cur = init_key("rc");

   key_f[0] = init_kkey("k1");
   key_f[1] = init_kkey("k2");
   key_f[2] = init_kkey("k3");
   key_f[3] = init_kkey("k4");
   key_f[4] = init_kkey("k5");
   key_f[5] = init_kkey("k6");
   key_f[6] = init_kkey("k7");
   key_f[7] = init_kkey("k8");
   key_f[8] = init_kkey("k9");
   key_f[9] = init_kkey("k;");
   key_f[10] = init_kkey("ku");
   key_f[11] = init_kkey("kd");
   key_f[12] = init_kkey("kl");
   key_f[13] = init_kkey("kr");
   key_f[14] = init_kkey("kI");
   key_f[15] = init_kkey("kh");
   key_f[16] = init_kkey("kP");
   key_f[17] = init_kkey("kD");
   key_f[18] = init_kkey("@7");
   key_f[19] = init_kkey("kN");
   key_f[20] = init_kkey("kb");
   key_f[21] = init_kkey("%1");
   key_f[22] = init_kkey("kH");
   key_f[23] = init_kkey("F7");
   key_f[24] = init_kkey("F8");
   key_f[25] = init_kkey("F9");
   key_f[26] = init_kkey("FA");
   key_f[27] = init_kkey("FB");
   key_f[28] = init_kkey("FC");
   key_f[29] = init_kkey("FD");
   key_f[30] = init_kkey("FE");
   key_f[31] = init_kkey("FF");
   key_f[32] = init_kkey("FG");
   key_f[33] = init_kkey("%e");
   key_f[34] = init_kkey("%c");
   key_f[35] = init_kkey("#4");
   key_f[36] = init_kkey("%i");
   key_f[37] = init_kkey("#2");
   key_f[38] = init_kkey("kR");
   key_f[39] = init_kkey("*7");
   key_f[40] = init_kkey("kF");
   key_f[41] = init_kkey("@1");
#endif
#ifdef NCURSES
   sp_chr[0] = ' ';
   sp_chr[1] = ACS_ULCORNER;
   sp_chr[2] = ACS_URCORNER;
   sp_chr[3] = ACS_LLCORNER;
   sp_chr[4] = ACS_LRCORNER;
   sp_chr[5] = ACS_HLINE;
   sp_chr[6] = ACS_VLINE;
   /* Scrollbar track/thumb: use the shaded board (ACS_CKBOARD, the CP437
      stipple) for the track and the solid block (ACS_BLOCK) for the thumb,
      mirroring the X11/Xft look (U+2591 light shade + U+2588 full block).
      The old ACS_S9 (a thin scan line, rendered as a column of 's' on
      terminals that lack the alt charset) and ACS_DIAMOND thumb looked
      broken on the Linux console.  CKBOARD/BLOCK exist in every VGA/console
      font, so the scrollbar reads as a real shaded gutter with a solid
      slider with no special font. */
   sp_chr[7] = ACS_CKBOARD;
   sp_chr[8] = ACS_VLINE;
   sp_chr[9] = ACS_VLINE;
   sp_chr[10] = ACS_CKBOARD;
   sp_chr[11] = ACS_BLOCK;
   sp_chr[12] = ' ';
#else
   sp_chr[0] = "";
   if(!(sp_chr[1] = init_spchr('l'))) sp_chr[1] = "+";
   if(!(sp_chr[2] = init_spchr('k'))) sp_chr[2] = "+";
   if(!(sp_chr[3] = init_spchr('m'))) sp_chr[3] = "+";
   if(!(sp_chr[4] = init_spchr('j'))) sp_chr[4] = "+";
   if(!(sp_chr[5] = init_spchr('q'))) sp_chr[5] = "-";
   if(!(sp_chr[6] = init_spchr('x'))) sp_chr[6] = "|";
   if(!(sp_chr[7] = init_spchr('w'))) sp_chr[7] = "_";
   if(!(sp_chr[8] = init_spchr('t'))) sp_chr[8] = "|";
   if(!(sp_chr[9] = init_spchr('m'))) sp_chr[9] = "|";
   if(!(sp_chr[10] = init_spchr('q'))) sp_chr[10] = "_";
   if(!(sp_chr[11] = init_spchr('`'))) sp_chr[11] = "#";
   if(!(sp_chr[12] = init_spchr('a'))) sp_chr[12] = " ";
#endif
   return(0);
}

int e_t_initscr()
{
 int ret, i, k;
#ifndef TERMCAP
 WINDOW * stdscr;
#endif

 ret = tcgetattr(1, &otermio); /* save old settings */
/*
 if(ret)
 {
  printf("Error in Terminal Initialisation Code: %d\n", ret);
  printf("c_iflag = %o, c_oflag = %o, c_cflag = %o,\n",
    otermio.c_iflag, otermio.c_oflag, otermio.c_cflag);
  printf("c_lflag = %o, c_line = %o, c_cc = {\"\\%o\\%o\\%o\\%o\\%o\\%o\\%o\\%o\"}\n",
    otermio.c_lflag, otermio.c_line, otermio.c_cc[0], otermio.c_cc[1], 
    otermio.c_cc[2], otermio.c_cc[3], otermio.c_cc[4], otermio.c_cc[5], 
    otermio.c_cc[6], otermio.c_cc[7]);
  WpeExit(1);
 }
*/
#ifndef TERMCAP
 if ((stdscr=initscr())==(WINDOW *)ERR) exit(27);
#ifdef NCURSES
 cbreak();
 noecho();
 nonl();
 intrflush(stdscr,FALSE);
 keypad(stdscr,TRUE);
 /* Deliver a bare Esc after 25ms instead of the ~1s default, so a single
    Esc closes dialogs/menus (no 3-press workaround that can be misread as
    an escape sequence and spin the File Manager). */
 set_escdelay(25);
#if MOUSE
 mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL);
 mouseinterval(0);
 e_mouse_tracking_enable();
#endif
#endif
 if (has_colors())
 {
  start_color();
  for (i = 0; i < COLORS; i++)
  {
   for (k = 0; k < COLORS; k++)
   {
    if (i != 0 || k != 0)
    {
     init_pair(i * 8 + k, k, i);
    }
   }
  }
 }
#endif
 e_begscr();
 schirm = calloc(MAXSCOL * MAXSLNS, sizeof(SCREENCELL));
 altschirm = calloc(MAXSCOL * MAXSLNS, sizeof(SCREENCELL));
#if !defined(NO_XWINDOWS) && defined(NEWSTYLE)
 extbyte = MALLOC(MAXSCOL * MAXSLNS);
#endif
 if(init_cursor())
 {
  printf("Terminal Not in the right mode\n");
  e_exit(1);
 }
 tcgetattr(0, &ntermio);
 ntermio.c_iflag = 0;            /* setup new settings */
 ntermio.c_oflag = 0;
 ntermio.c_lflag = 0;
 ntermio.c_cc[VMIN] = 1;
 ntermio.c_cc[VTIME] = 0;
#ifdef VSWTCH
 ntermio.c_cc[VSWTCH] = 0;
#endif
 tcsetattr(0, TCSADRAIN, &ntermio);
 if (spc_in) e_putp(spc_in);
 return(0);
}

int svflgs, kbdflgs;

int e_begscr()
{
 int cols, lns;

 kbdflgs = fcntl( 0, F_GETFL, 0 );
#ifndef TERMCAP
#ifndef NCURSES
 setupterm((char *)0, 1, (int *)0);
#endif
 if ((lns = tigetnum("lines")) > 0)
  MAXSLNS = lns;
 if ((cols = tigetnum("cols")) > 0)
  MAXSCOL = cols;
#else
 if ((tc_screen = getenv("TERM")) == NULL)
  e_exitm("Environment variable TERM not defined!", 1);
 if ((tgetent(tcbuf, tc_screen)) != 1)
  e_exitm("Unknown terminal type!", 1);
 if ((lns = tgetnum("li")) > 0)
  MAXSLNS = lns;
 if ((cols = tgetnum("co")) > 0)
  MAXSCOL = cols;
#endif
 return(0);
}

#define fk_putp(p) ( p ? e_putp(p) : e_putp(att_no) )

void e_endwin()
{
#ifdef NCURSES
#if MOUSE
 e_mouse_tracking_disable();
#endif
 endwin();
#else
 fk_putp(ratt_bo);
#endif
 tcsetattr(0, TCSADRAIN, &otermio);
}

int fk_t_cursor(int x)
{
 return(x);
}

int fk_t_putchar(int c)
{
#ifdef NCURSES
 addch(c);
 return c;
#else
 return(fputc(c, stdout));
#endif
}

int fk_attrset(int a)
{
 if(cur_attr == a) return(0);
#ifdef NCURSES
 switch(a)
 {  case 0:  attrset(A_NORMAL);  break;
    case 1:  attrset(A_STANDOUT);  break;
    case 2:  attrset(A_UNDERLINE);  break;
    case 4:  attrset(A_REVERSE);  break;
    case 8:  attrset(A_BLINK);  break;
    case 16:  attrset(A_DIM);  break;
    case 32:  attrset(A_BOLD);  break;
 }
#else
 switch(cur_attr)
 {  case 0:  fk_putp(ratt_no);  break;
    case 1:  fk_putp(ratt_so);  break;
    case 2:  fk_putp(ratt_ul);  break;
    case 4:  fk_putp(ratt_rv);  break;
    case 8:  fk_putp(ratt_bl);  break;
    case 16:  fk_putp(ratt_dm);  break;
    case 32:  fk_putp(ratt_bo);  break;
 }
 switch(a)
 {  case 0:  fk_putp(att_no);  break;
    case 1:  fk_putp(att_so);  break;
    case 2:  fk_putp(att_ul);  break;
    case 4:  fk_putp(att_rv);  break;
    case 8:  fk_putp(att_bl);  break;
    case 16:  fk_putp(att_dm);  break;
    case 32:  fk_putp(att_bo);  break;
 }
#endif
 return(cur_attr = a);
}

void fk_colset(int c)
{
 int bg;
 if (cur_attr == c) return;
 cur_attr = c;
 bg = c / 16;
#ifdef TERMCAP
 if ((c %= 16) >= col_num)
 {
  fk_putp(att_bo);
  e_putp(tgoto(col_fg, 0, c % col_num));
  e_putp(tgoto(col_bg, 0, bg));
 }
 else
 {
  fk_putp(ratt_bo);
  e_putp(tgoto(col_fg, 0, c));
  e_putp(tgoto(col_bg, 0, bg));
 }
#else
#ifdef NCURSES
 if (c & 8)
  attrset(A_BOLD);
 else
  attrset(A_NORMAL);
 color_set((bg * 8) + c % 8, NULL);
#else
 if ((c %= 16) >= col_num)
 {
  fk_putp(att_bo);
  e_putp(tparm1(col_fg, c % col_num));
  e_putp(tparm1(col_bg, bg));
 }
 else
 {
  fk_putp(ratt_bo);
  e_putp(tparm1(col_fg, c));
  e_putp(tparm1(col_bg, bg));
 }
#endif
#endif
}

int e_t_refresh()
{
 int x = cur_x, y = cur_y, i, j, c;
 int ref_slns, ref_scol;
 sigset_t block, prev;
 sigemptyset(&block);
 sigaddset(&block, SIGWINCH);
 sigprocmask(SIG_BLOCK, &block, &prev);
 ref_slns = MAXSLNS < LINES ? MAXSLNS : LINES;
 ref_scol = MAXSCOL < COLS  ? MAXSCOL : COLS;
 fk_cursor(0);
 for(i = 0; i < ref_slns; i++)
  for(j = 0; j < ref_scol; j++)
  {
   if (i == ref_slns-1 && j == ref_scol-1) break;
   if (schirm[i * MAXSCOL + j].ch != altschirm[i * MAXSCOL + j].ch ||
     schirm[i * MAXSCOL + j].attr != altschirm[i * MAXSCOL + j].attr)
   {
    if (cur_x != j || cur_y != i)
     term_move(j, i);
    if (cur_x < MAXSCOL)
    {  cur_x = j + 1;  cur_y = i;  }
    else
    {  cur_x = 0;  cur_y = i+1;  }
    if (col_num <= 0)
     fk_attrset(e_gt_col(j, i));
    else
     fk_colset(e_gt_col(j, i));
    c = e_gt_char(j, i);
    /* Sanitise: reject values that xwpe cannot have produced.
       Valid: 0-12 (sp_chr border/scrollbar chars), 32-127 (ASCII),
       128+ only if wcwidth >= 0 (printable Unicode from UTF-8 decode).
       Everything else is uninitialised SCREENCELL data.
       Fix schirm in place so the garbage is not saved by e_open_view
       and propagated through pic->p save/restore cycles. */
    if (c < 0 || (c >= NSPCHR && c < 32) ||
        (c > 127 && wcwidth((wchar_t)c) < 0))
    {
     c = ' ';
     e_pr_char(j, i, ' ', 0);
    }
#ifdef NCURSES
    if (c < NSPCHR)
     addch(sp_chr[c]);
    else if (c > 127)
    {
     /* Wide character: output via add_wch for proper positioning */
     cchar_t cc;
     wchar_t wc[2] = { (wchar_t)c, 0 };
     int cw = wcwidth((wchar_t)c);
     setcchar(&cc, wc, A_NORMAL, 0, NULL);
     add_wch(&cc);
     /* Skip placeholder cells for wide chars (emoji, CJK = 2 columns) */
     if (cw > 1)
     {
      int k;
      for (k = 1; k < cw && j+k < MAXSCOL; k++)
       altschirm[(i) * MAXSCOL + (j+k)] = schirm[(i) * MAXSCOL + (j+k)];
      j += cw - 1;
      cur_x = j + 1;
     }
    }
    else if (c >= NSPCHR)
     addch(c);
    /* else: c < 0 -- skip uninitialised/invalid cell */
#else
    if (c < NSPCHR)
     e_putp(sp_chr[c]);
    else
     fputc(c, stdout);
#endif
    altschirm[i * MAXSCOL + j] = schirm[i * MAXSCOL + j];
   }
  }
 fk_cursor(1);
 fk_locate(x, y);
 term_refresh();
 sigprocmask(SIG_SETMASK, &prev, NULL);
 return(0);
}

int e_t_sys_ini()
{
 e_refresh();
 tcgetattr(0, &ttermio);
 svflgs = fcntl( 0, F_GETFL, 0 );
 e_endwin();
 return(0);   
}

/**
 * e_t_rearm_mouse - Make window drag/resize work again after running a tool.
 *
 * Used when returning to the editor from a sub-process (e.g. an F9 compile),
 * which had to hand the real terminal to the tool and so turned off mouse
 * motion reporting. Without re-arming it the user can still click, but
 * dragging a title bar to move a window or a corner to resize it silently does
 * nothing. The motion escape must be emitted AFTER the screen is restored,
 * because some terminals reset the mouse mode when the screen is switched back;
 * we flush that screen switch first, then re-enable tracking last.
 */
static void e_t_rearm_mouse(void)
{
 refresh();                  /* flush ncurses ca-mode re-entry (1049h) first */
 e_mouse_tracking_enable();  /* then the motion-tracking escape, emitted last */
}

int e_t_sys_end()
{
 tcsetattr(0, TCSADRAIN, &ttermio);
 fcntl( 0, F_SETFL, svflgs );
 e_abs_refr();
 e_t_rearm_mouse();
 fk_locate(0, 0);
 return(0);
}

int e_t_kbhit()
{
 int ret;
 char kbdflgs, c;

 e_refresh();
 kbdflgs = fcntl(0, F_GETFL, 0 );
 fcntl(0, F_SETFL, kbdflgs | O_NONBLOCK);
 ret = read(0, &c, 1);
 fcntl(0, F_SETFL, kbdflgs & ~O_NONBLOCK);
 return (ret == 1 ? c : 0);
}

#ifdef NCURSES
static int e_t_utf8_assemble(int first)
{
 int cp, i, expect;
 int cont;

 if ((first & 0xE0) == 0xC0)
  { cp = first & 0x1F; expect = 1; }
 else if ((first & 0xF0) == 0xE0)
  { cp = first & 0x0F; expect = 2; }
 else if ((first & 0xF8) == 0xF0)
  { cp = first & 0x07; expect = 3; }
 else
  return first;
 for (i = 0; i < expect; i++)
 {
  timeout(50);
  cont = fk_getch();
  if (cont == ERR || (cont & 0xC0) != 0x80)
   return first;
  cp = (cp << 6) | (cont & 0x3F);
 }
 return cp;
}

static int e_t_getch_poll(void)
{
 static int stdin_registered = 0;
 extern int e_d_async_pending;
 extern void e_d_place_cursor_in_messages(void);
 int c;
#ifdef HAVE_LIBGPM
 /* GPM (bare Linux console) delivers mouse events on its own fd, not stdin.
    ncurses does not pump it here (we opened the gpm connection ourselves), so
    the input loop must poll gpm_fd and drain it via WpeGpmReadable -- otherwise
    the pointer never moves and clicks never register on the console. */
 static int gpm_registered = 0;
 extern int g_gpm_click_pending;
 void WpeGpmReadable(int fd, void *data);
 int WpeGpmFd(void);
#endif

 if (!stdin_registered)
 {
  wpe_fd_add(STDIN_FILENO, POLLIN, NULL, NULL);
  stdin_registered = 1;
 }
#ifdef HAVE_LIBGPM
 if (!gpm_registered)
 {
  int gfd = WpeGpmFd();
  if (gfd >= 0)
  {
   wpe_fd_add(gfd, POLLIN, WpeGpmReadable, NULL);
   gpm_registered = 1;
  }
 }
#endif
 for (;;)
 {
  timeout(50);
  c = fk_getch();
  timeout(-1);
  if (c != ERR)
  {
   if ((unsigned int)c >= 0xC0 && (unsigned int)c <= 0xF7)
    c = e_t_utf8_assemble(c);
   return c;
  }
  if (e_d_async_pending)
   e_d_place_cursor_in_messages();
  wpe_fd_poll(-1);
#ifdef HAVE_LIBGPM
  if (g_gpm_click_pending)
  {
   g_gpm_click_pending = 0;   /* e_mouse already filled by WpeGpmHandler */
   return (-1);
  }
#endif
 }
}

/* After a bare ESC, wait at most this long (ms) for a following byte before
   deciding it was Esc alone. An Alt-<key> combo sends ESC and the key together,
   so they arrive within this window; a lone Esc does not. Matches the ncurses
   set_escdelay(25) above. */
#define ESC_ALT_DELAY_MS 25

int e_t_getch()
{
 int c, bk;
 extern int g_mouse_buttons;

 e_refresh();
 c = e_t_getch_poll();
 if (c > KEY_CODE_YES)
 {
  switch (c)
  {
   case KEY_F(1):  c = F1; break;
   case KEY_F(2):  c = F2; break;
   case KEY_F(3):  c = F3; break;
   case KEY_F(4):  c = F4; break;
   case KEY_F(5):  c = F5; break;
   case KEY_F(6):  c = F6; break;
   case KEY_F(7):  c = F7; break;
   case KEY_F(8):  c = F8; break;
   case KEY_F(9):  c = F9; break;
   case KEY_F(10):  c = F10; break;
   case KEY_UP:  c = CUP; break;
   case KEY_DOWN:  c = CDO; break;
   case KEY_LEFT:  c = CLE; break;
   case KEY_RIGHT:  c = CRI; break;
   case KEY_IC:  c = EINFG; break;
   case KEY_DC:  c = ENTF; break;
   case KEY_PPAGE:  c = BUP; break;
   case KEY_NPAGE:  c = BDO; break;
   case KEY_HOME:  c = POS1; break;
   case KEY_END:  c = ENDE; break;
   case KEY_BTAB:  c = WPE_BTAB; break;
   case KEY_RESIZE:
   {
    int i, old_scol = MAXSCOL, old_slns = MAXSLNS;
    /* Drain any queued KEY_RESIZE events (resize often arrives in
       bursts).  Same technique as dialog(1) dlg_will_resize(). */
    { int _ch;
      nodelay(stdscr, TRUE);
      while ((_ch = getch()) == KEY_RESIZE)
       ;
      if (_ch != ERR)
       ungetch(_ch);
      nodelay(stdscr, FALSE);
    }
    /* ncurses already called resizeterm() and updated LINES/COLS */
    MAXSCOL = COLS;
    MAXSLNS = LINES;
    if (MAXSLNS < 6) MAXSLNS = 6;
    if (MAXSCOL < 30) MAXSCOL = 30;
    if (MAXSCOL != old_scol || MAXSLNS != old_slns)
    {
     schirm = REALLOC(schirm, sizeof(SCREENCELL) * MAXSCOL * MAXSLNS);
     altschirm = REALLOC(altschirm, sizeof(SCREENCELL) * MAXSCOL * MAXSLNS);
     memset(schirm, 0, sizeof(SCREENCELL) * MAXSCOL * MAXSLNS);
     memset(altschirm, 0, sizeof(SCREENCELL) * MAXSCOL * MAXSLNS);
#if !defined(NO_XWINDOWS) && defined(NEWSTYLE)
     extbyte = REALLOC(extbyte, MAXSCOL * MAXSLNS);
#endif
     e_relayout_windows(WpeEditor, old_scol, old_slns);
     e_free_all_pics(WpeEditor);
     e_repaint_desk(WpeEditor->f[WpeEditor->mxedt]);
    }
    return WPE_RESIZE;
   }
   case KEY_BACKSPACE:  c = WPE_DC; break;
#if MOUSE
   case KEY_MOUSE:
   {
    MEVENT mev;
    if (getmouse(&mev) == OK)
    {
     extern struct mouse e_mouse;
     int btn = e_t_mouse_decode_button(mev.bstate);
     e_mouse.x = mev.x;
     e_mouse.y = mev.y;
     if (btn >= 0)
      g_mouse_buttons |= btn;
     else if (e_t_mouse_is_released(mev.bstate))
      g_mouse_buttons = 0;
     e_mouse.k = g_mouse_buttons;
     return(-1);
    }
    c = 0;
    break;
   }
#endif
   case KEY_HELP:  c = HELP; break;
   case KEY_LL:  c = ENDE; break;
   case KEY_F(17):  c = SF1; break;
   case KEY_F(18):  c = SF2; break;
   case KEY_F(19):  c = SF3; break;
   case KEY_F(20):  c = SF4; break;
   case KEY_F(21):  c = SF5; break;
   case KEY_F(22):  c = SF6; break;
   case KEY_F(23):  c = SF7; break;
   case KEY_F(24):  c = SF8; break;
   case KEY_F(25):  c = SF9; break;
   case KEY_F(26):  c = SF10; break;
   /* Modern terminals (xterm modifyOtherKeys, gnome/vte, kitty) report
      Ctrl-/Alt-modified function keys as distinct ncurses keycodes in the
      standard ranges -- Ctrl-Fn = KEY_F(24+n), Alt-Fn = KEY_F(48+n) -- which
      the offset-via-bioskey() path cannot recover because bioskey() reads the
      Linux-console keyboard state and returns 0 in an emulator.  Map the ones
      xwpe binds as shortcuts so they work in a terminal emulator too, not
      only on a bare VT.  (A full Shift/Ctrl/Alt function-key table for all
      terminals is a 1.6.4 cleanup -- see TODO.) */
   case KEY_F(33):  c = CF9; break;   /* Ctrl-F9  -> Run program        */
   case KEY_F(53):  c = AF5; break;   /* Alt-F5   -> Borland User Screen */
   case KEY_PREVIOUS:  c = CUP+512; break;
   case KEY_NEXT:  c = CDO+512; break;
   default:  c = 0; break;
  }
  bk = bioskey();
  if (bk & 3)
   c += 512;
  else if (bk & 4)
   c += 514;
 }
 else if ( c == WPE_TAB )
 {
  bk = bioskey(); 
  if ( bk & 3)
   c = WPE_BTAB;
  else
   c = WPE_TAB;
 }
 else if (c == WPE_ESC)
 {
  /* A lone Esc must register on the first press. Wait only briefly for a
     following byte: an Alt-<key> combo sends ESC+key together (arrives within
     the window), a lone Esc does not -- so do not block for a second press.
     Fixes "Esc needs several presses" on the Linux console. */
  timeout(ESC_ALT_DELAY_MS);
  c = fk_getch();
  timeout(-1);
  if (c == ERR)
   return(WPE_ESC);
  if (c > KEY_CODE_YES)
  {
   switch (c)
   {
    case KEY_F(1):  c = AF1; break;
    case KEY_F(2):  c = AF2; break;
    case KEY_F(3):  c = AF3; break;
    case KEY_F(4):  c = AF4; break;
    case KEY_F(5):  c = AF5; break;
    case KEY_F(6):  c = AF6; break;
    case KEY_F(7):  c = AF7; break;
    case KEY_F(8):  c = AF8; break;
    case KEY_F(9):  c = AF9; break;
    case KEY_F(10):  c = AF10; break;
    case KEY_UP:  c = BUP; break;
    case KEY_DOWN:  c = BDO; break;
    case KEY_LEFT:  c = CCLE; break;
    case KEY_RIGHT:  c = CCRI; break;
    case KEY_IC:  c = EINFG+512; break;
    case KEY_DC:  c = ENTF+512; break;
    case KEY_PPAGE:  c = CBUP; break;
    case KEY_NPAGE:  c = CBDO; break;
    case KEY_HOME:  c = CPS1; break;
    case KEY_END:  c = CEND; break;
    case KEY_BACKSPACE:  c = AltBS; break;
    case KEY_HELP:  c = AF1; break;
    case KEY_LL:  c = CEND; break;
    case KEY_PREVIOUS:  c = BUP+512; break;
    case KEY_NEXT:  c = BDO+512; break;
    default:  c = 0; break;
   }
   bk = bioskey();
   if (bk & 3)
    c += 512;
   else if (bk & 4)
    c += 514;
  }
  else if (c != WPE_ESC)
   c = e_tast_sim(c);
 }
 return(c);
}

#else
int e_t_getch()
{
 int c, c2, pshift, bk;

 pshift = 0;
 e_refresh();
 if ((c = fk_getch()) != WPE_ESC)
 {
  if (key_f[20] && c == *key_f[20])
   return(WPE_DC);
  else if (key_f[17] && c == *key_f[17])
   return(ENTF);
  else if ( c == WPE_TAB )
  {
   bk = bioskey(); 
   if (bk & 3) 
    return (WPE_BTAB); 
   else
    return (WPE_TAB); 
  }
  else
   return(c);
 }
 else if ((c = fk_getch()) == WPE_CR)
  return(WPE_ESC);
 bk = bioskey();
 if (bk & 3)
  pshift = 512;
 else if (bk & 4)
  pshift = 514;
 if (c == WPE_ESC)
 {
  if ((c = fk_getch()) == WPE_ESC)
   return(WPE_ESC);
  if ((c2 = e_find_key(c, 1, 1)))
   return(c2 + pshift);
 }
 if ((c2 = e_find_key((char)c, 1, 0)))
  return(c2 + pshift);
 return(e_tast_sim(c + pshift));
}

char e_key_save[10];

int e_find_key(int c, int j, int sw)
{
   int i, k;
   e_key_save[j] = c;
   e_key_save[j+1] = '\0';
   for(i = 0; i < KEYFN; i++)
   {  if(key_f[i] == NULL) continue;
      for(k = 1; k <= j && e_key_save[k] == *(key_f[i] + k); k++);
      if(k > j)
      {  if(*(key_f[i] + k) != '\0') return(e_find_key(fk_getch(), j+1, sw));
	 else if(sw)
	 {  switch(i)
	    {  case 0:  return(AF1);
	       case 1:  return(AF2);
	       case 2:  return(AF3);
	       case 3:  return(AF4);
	       case 4:  return(AF5);
	       case 5:  return(AF6);
	       case 6:  return(AF7);
	       case 7:  return(AF8);
	       case 8:  return(AF9);
	       case 9:  return(AF10);
	       case 10:  return(BUP);
	       case 11:  return(BDO);
	       case 12:  return(CCLE);
	       case 13:  return(CCRI);
	       case 14:  return(EINFG);
	       case 15:  return(CPS1);
	       case 16:  return(CBUP);
	       case 17:  return(ENTF);
	       case 18:  return(CEND);
	       case 19:  return(CBDO);
	       case 20:  return(AltBS);
	       case 21:  return(AF1);
	       case 22:  return(CEND);
	       case 33:  return(BUP+512);
	       case 34:  return(BDO+512);
	       case 35:  return(CCLE+512);
	       case 36:  return(CCRI+512);
	       case 37:  return(CPS1+512);
	       case 38:  return(CBUP+512);
	       case 39:  return(CEND+512);
	       case 40:  return(CBDO+512);
	       case 41:  return(CEND);
	       default:  return(0);
	    }
	 }
	 else
	 {  switch(i)
	    {  case 0:  return(F1);
	       case 1:  return(F2);
	       case 2:  return(F3);
	       case 3:  return(F4);
	       case 4:  return(F5);
	       case 5:  return(F6);
	       case 6:  return(F7);
	       case 7:  return(F8);
	       case 8:  return(F9);
	       case 9:  return(F10);
	       case 10:  return(CUP);
	       case 11:  return(CDO);
	       case 12:  return(CLE);
	       case 13:  return(CRI);
	       case 14:  return(EINFG);
	       case 15:  return(POS1);
	       case 16:  return(BUP);
	       case 17:  return(ENTF);
	       case 18:  return(ENDE);
	       case 19:  return(BDO);
	       case 20:  return(WPE_DC);
	       case 21:  return(HELP);
	       case 22:  return(ENDE);
	       case 23:  return(SF1);
	       case 24:  return(SF2);
	       case 25:  return(SF3);
	       case 26:  return(SF4);
	       case 27:  return(SF5);
	       case 28:  return(SF6);
	       case 29:  return(SF7);
	       case 30:  return(SF8);
	       case 31:  return(SF9);
	       case 32:  return(SF10);
	       case 33:  return(CUP+512);
	       case 34:  return(CDO+512);
	       case 35:  return(CLE+512);
	       case 36:  return(CRI+512);
	       case 37:  return(POS1+512);
	       case 38:  return(BUP+512);
	       case 39:  return(ENDE+512);
	       case 40:  return(BDO+512);
	       case 41:  return(ENDE);
	       default:  return(0);
	    }
	 }
      }
   }
   return(0);
}
#endif

int fk_t_locate(int x, int y)
{
 if (col_num > 0) 
 {
  fk_colset(e_gt_col(cur_x, cur_y));
#ifdef NCURSES
  /* Causes problems.  Reason unknown. - Dennis */
  /*mvaddch(cur_y,cur_x,e_gt_char(cur_x, cur_y));*/
#else
  fputc(e_gt_char(cur_x, cur_y), stdout);
#endif
 }
 cur_x = x;
 cur_y = y;
 term_move(x, y);
 return(y);
}

static int e_t_mouse_decode_button(mmask_t bstate)
{
 if (bstate & (BUTTON1_PRESSED|BUTTON1_CLICKED)) return 1;
 if (bstate & (BUTTON2_PRESSED|BUTTON2_CLICKED)) return 2;
 if (bstate & (BUTTON3_PRESSED|BUTTON3_CLICKED)) return 4;
 return -1;
}

static int e_t_mouse_is_released(mmask_t bstate)
{
 return (bstate & (BUTTON1_RELEASED|BUTTON2_RELEASED|BUTTON3_RELEASED)) != 0;
}

int fk_t_mouse(int *g)
{
#if MOUSE
 extern struct mouse e_mouse;
 MEVENT mev;
 int btn, ch;

 if (g[0] == 2)
  return(0);
 timeout(50);
 ch = getch();
 timeout(-1);
 if (ch == KEY_MOUSE && getmouse(&mev) == OK)
 {
  btn = e_t_mouse_decode_button(mev.bstate);
  if (btn >= 0)
   g_mouse_buttons |= btn;
  else if (e_t_mouse_is_released(mev.bstate))
   g_mouse_buttons = 0;

  g[1] = g_mouse_buttons;
  g[2] = mev.x * 8;
  g[3] = mev.y * 8;
  e_mouse.x = mev.x;
  e_mouse.y = mev.y;
  e_mouse.k = g_mouse_buttons;
 }
 else
 {
  g[1] = g_mouse_buttons;
  g[2] = e_mouse.x * 8;
  g[3] = e_mouse.y * 8;
  if (ch != ERR)
   ungetch(ch);
 }
 return(0);
#else
 return(0);
#endif
}

int e_t_switch_screen(int sw)
{
 static int sav_sw = -1;

 if (sw == sav_sw)
  return(0);
 sav_sw = sw;
 if (sw && beg_scr) 
 {
  term_refresh();
  if (sav_cur)
   e_putp(sav_cur);
  e_putp(beg_scr);
 }
 else if (!sw && swt_scr)
 {
  e_putp(swt_scr);
  if (res_cur)
   e_putp(res_cur);
  term_refresh();
 }
 else
  return(-1);
 return(0);
}

/**
 * e_t_deb_out - Show the program's output (Ctrl-G P / Alt-F5 "Output").
 *
 * The program's stdout/stderr is captured into the Messages window (via the
 * pty drain) in BOTH the terminal and X11 builds, so this is uniform across
 * backends now: raise and focus the Messages panel and scroll to the latest
 * output, the way a modern IDE focuses its integrated output panel.  No
 * backend-specific behaviour, no modal popup, no screen switch.
 *
 * The classic full-screen "user screen" (for programs that paint with cursor
 * positioning or ANSI colour) lives in e_t_user_screen() below; it is not
 * yet bound to a key -- a faithful version (integrated terminal) is planned
 * for a later release.
 */
int e_t_deb_out(FENSTER *f)
{
 extern int e_p_show_program_output(FENSTER *);
 return e_p_show_program_output(f);
}

/**
 * e_t_user_screen - Switch the console to the program's raw full-screen output.
 *
 * Terminal-only.  Drops out of ncurses (endwin), clears the screen and
 * replays the captured program output verbatim, then waits for a keypress
 * before returning to the editor -- the Borland "User Screen" (Alt-F5).
 * Unlike the Messages panel this can show a program that paints (cursor
 * positioning, ANSI colour), because it hands the real terminal back to it.
 *
 * NOT bound to a key yet: the captured buffer is empty after a plain Run and
 * cannot faithfully reproduce a painting program.  The proper version (an
 * integrated VT terminal shared by both backends) is planned for 1.6.4; this
 * function is kept ready to wire to Alt-F5 then.
 */
int e_t_user_screen(FENSTER *f)
{
 extern char *e_d_prog_output;
 extern int e_d_prog_output_len;
 extern void e_d_pty_drain(void);
 int i;
 (void)f;

 e_d_pty_drain();
 endwin();
 /* Borland's "User Screen": leave the editor and show the program's own
    full screen.  Replay the captured output VERBATIM -- the bytes the program
    wrote to its terminal, including cursor positioning, ANSI colour and box
    drawing -- so a program that PAINTS shows exactly as it left the screen.
    No headers and no \n->\r\n rewriting (the pty already emits \r\n), which
    would otherwise corrupt cursor-addressed output. */
 (void) i;
 fputs("\033[2J\033[H", stderr);
 if (e_d_prog_output && e_d_prog_output_len > 0)
  fwrite(e_d_prog_output, 1, e_d_prog_output_len, stderr);
 else
  fputs("(no program output yet -- run with Ctrl-F9 or start a debug session)",
    stderr);
 /* A discreet, reverse-video prompt on its own line so it does not paint over
    the program's last line. */
 fputs("\033[0m\r\n\033[7m xwpe: press any key to return to the editor \033[0m",
   stderr);
 fflush(stderr);
 { struct termios _old, _raw; char _c;
   tcgetattr(0, &_old);
   _raw = _old;
   _raw.c_lflag &= ~(ICANON | ECHO);
   _raw.c_cc[VMIN] = 1;
   _raw.c_cc[VTIME] = 0;
   tcsetattr(0, TCSANOW, &_raw);
   read(0, &_c, 1);
   tcsetattr(0, TCSANOW, &_old);
 }
 clearok(stdscr, TRUE);
 refresh();
 return(0);
}

int e_d_switch_screen(int sw)
{
#ifdef DEBUGGER
 if (!sw)
  e_g_sys_ini();
 else
  e_g_sys_end();
#endif
 return(e_switch_screen(sw));
}

int e_t_d_switch_out(int sw)
{
 static int save_sw = 32000;

 if (save_sw == sw)
  return(0);
 save_sw = sw;
 /* In terminal mode, program output is redirected to a file (not the
    tty), so no screen switching is needed during F7/F8 stepping.
    This eliminates the flicker that the original design caused by
    toggling between alternate and normal screen on every step.
    Just repaint the editor when returning from a debug command. */
 if (!sw)
 {
  /* No clearok needed: with pty output capture, the screen was never
     switched away, so ncurses' state is still valid. Just refresh. */
  e_refresh();
 }
 return(sw);
}

void e_exitm(char *s, int n)
{
 e_endwin();
 if (n != 0)
  printf("\n%s\n", s);
 exit(n);
}

int e_s_sys_ini()
{
 e_sys_ini();
 return(e_switch_screen(0));
}

int e_s_sys_end()
{
 e_switch_screen(1);
 return(e_sys_end());
}

#endif  /*  Is UNIX       */

