/*
 * $Id: io-curses.c,v 1.20 2001/02/13 23:38:06 danny Exp $
 *
 * Copyright © 1992, 1993, 1999, 2001 Free Software Foundation, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this software; see the file COPYING.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 */


#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifdef	WITH_DMALLOC
#include <dstdlib.h>
#endif

#include "proto.h"
#include "funcdef.h"
#include <stdio.h>

#if defined(HAVE_LIBNCURSES) && defined(HAVE_NCURSES_H)
#include <ncurses.h>
#else
#include <curses.h>
#endif

#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <signal.h>
#undef NULL
#include "sysdef.h"
#include "global.h"
#include "cell.h"
#include "cmd.h"
#include "line.h"
#include "io-generic.h"
#include "io-edit.h"
#include "io-term.h"
#include "io-abstract.h"
#include "io-utils.h"
#include "lists.h"
#include "regions.h"
#include "window.h"
#include "key.h"
#include "input.h"
#include "info.h"
#include <term.h>

#define MIN_WIN_HEIGHT	(cwin->flags&WIN_EDGES ? 2 : 1)
#define MIN_WIN_WIDTH	(cwin->flags&WIN_EDGES ? 6 : 1)

static int redrew = 0;
static int textout = 0;
static int term_cursor_claimed = 0;

static void move_cursor_to (struct window *, CELLREF, CELLREF, int);

static int
curses_metric (char * str, int len)
{
  return len;
}

static struct input_view input_view
  = {0, curses_metric, curses_metric, 0, 0, 0, 0, 0, 0, 0, 0, 0};

static void
_io_redraw_input (void)
{
  int pos;
  int row = (input_view.current_info ? 0 : Global->input);

  if (input_view.info_redraw_needed)
    {
      input_view.info_redraw_needed = 0;
      io_repaint ();
      return;
    }

  if (input_view.redraw_needed == NO_REDRAW)
    return;

  if (input_view.redraw_needed == FULL_REDRAW)
    {
      /* Redraw	the prompt. */ 
      move (row, 0);
      if (input_view.expanded_keymap_prompt)
	{
	  addstr (input_view.expanded_keymap_prompt);
	  clrtoeol ();
	  input_view.redraw_needed = NO_REDRAW;
	  return;
	}
      if (input_view.prompt_wid)
	addstr (input_view.prompt);
      pos = input_view.visibility_begin;
    }
  else
    {
      pos = input_view.redraw_needed;
      move (row,
	    input_view.prompt_wid + pos - input_view.visibility_begin);
    }
    
  if (   input_view.input_area
      && (input_view.visibility_end >= input_view.visibility_begin)
      && (input_view.visibility_begin < strlen (input_view.input_area->buf)))
    {
      int x;
      for (x = pos; x <= input_view.visibility_end; ++x)
	addch (input_view.input_area->buf[x]);
    }
  clrtoeol ();
  input_view.redraw_needed = NO_REDRAW;
}


#undef MIN
#define MIN(A,B) (((A) < (B)) ? (A) : (B))

void
redraw_info (void)
{
  if (!input_view.current_info)
    return;
  {
    int ipos = input_view.info_pos;
    int stop = MIN (input_view.current_info->len, Global->scr_lines - 1 + ipos);
    while (ipos < stop)
      {
	move (1 + ipos - input_view.info_pos, 0);
	addstr (input_view.current_info->text[ipos]);
	clrtoeol ();
	++ipos;
      }
  }
  _io_redraw_input ();
}


static void
_io_fix_input (void)
{
  iv_fix_input (&input_view);
}

static void
_io_move_cursor (void)
{
  iv_move_cursor (&input_view);
}

static void
_io_erase (int len)
{
  iv_erase (&input_view, len);
}

static void
_io_insert (int len)
{
  iv_insert (&input_view, len);
}
	   
static void
_io_over (char * str, int len)
{
  iv_over (&input_view, len);
}

static void 
_io_display_cell_cursor (void)
{
  int cell_cursor_row;
  int cell_cursor_col;
  int cc;
  int rr;
  int cwid;
  int n;
  int x, y;

  if (input_view.current_info)
    return;

  if (   (curow < cwin->screen.lr)
      || (cucol < cwin->screen.lc)
      || (curow > cwin->screen.hr)
      || (cucol > cwin->screen.hc))
    return;

  getyx (stdscr, y, x);
  cell_cursor_col = cwin->win_over;
  for (cc = cwin->screen.lc; cc < cucol; cc++)
    cell_cursor_col += get_width (cc);
  cell_cursor_row = cwin->win_down;
  for (rr = cwin->screen.lr; rr < curow; rr++)
    cell_cursor_row += get_height (rr);
  cwid = get_width (cucol);
  if (cwid > cwin->numc)
    cwid = cwin->numc;
  move (cell_cursor_row, cell_cursor_col);
  standout ();
  for (n = cwid; n; n--)
#ifdef A_STANDOUT
    addch (inch () | A_STANDOUT);
#else
    addch (inch ());
#endif
  standend ();
  move (y, x);
}

static void 
_io_hide_cell_cursor (void)
{
  int cc;
  int rr;
  int cell_cursor_row;
  int cell_cursor_col;
  int cwid;
  int n;
  int x, y;

  if (input_view.current_info)
    return;
  if (   (curow < cwin->screen.lr)
      || (cucol < cwin->screen.lc)
      || (curow > cwin->screen.hr)
      || (cucol > cwin->screen.hc))
    return;
  getyx (stdscr, y, x);
  cell_cursor_col = cwin->win_over;
  for (cc = cwin->screen.lc; cc < cucol; cc++)
    cell_cursor_col += get_width (cc);
  cell_cursor_row = cwin->win_down;
  for (rr = cwin->screen.lr; rr < curow; rr++)
    cell_cursor_row += get_height (rr);
  cwid = get_width (cucol);
  if (cwid > cwin->numc)
    cwid = cwin->numc;
  move (cell_cursor_row, cell_cursor_col);
  for (n = cwid; n; n--)
#ifdef A_STANDOUT
    addch (inch () & ~A_STANDOUT);
#else
    addch (inch ());
#endif
  move (y, x);
}

/* Functions, etc for dealing with cell contents being displayed
	on top of other cells. */

struct slops
{
  int s_alloc, s_used;
  struct s
    {
      CELLREF row, clo, chi;
    } s_b[1];
};

static void 
flush_slops (VOIDSTAR where)
{
  struct slops *s;

  s = where;
  if (s)
    s->s_used = 0;
}

static int 
find_slop (VOIDSTAR where, CELLREF r, CELLREF c, CELLREF *cclp, CELLREF *cchp)
{
  int n;
  struct slops *s;

  s = where;
  if (!s)
    return 0;
  for (n = 0; n < s->s_used; n++)
    {
      if (s->s_b[n].row == r && s->s_b[n].clo <= c && s->s_b[n].chi >= c)
	{
	  *cclp = s->s_b[n].clo;
	  *cchp = s->s_b[n].chi;
	  return 1;
	}
    }
  return 0;
}

static void 
kill_slop (VOIDSTAR where, CELLREF r, CELLREF clo, CELLREF chi)
{
  int n;
  struct slops *s;

  s = where;
  for (n = 0; n < s->s_used; n++)
    {
      if (s->s_b[n].row == r && s->s_b[n].clo == clo && s->s_b[n].chi == chi)
	{
	  --(s->s_used);
	  s->s_b[n] = s->s_b[s->s_used];
	  return;
	}
    }
}

static void 
set_slop (VOIDSTAR *wherep, CELLREF r, CELLREF clo, CELLREF chi)
{
  int n;
  struct slops **sp;

  sp = (struct slops **) wherep;
  if (!*sp)
    {
      (*sp) = ck_malloc (sizeof (struct slops) + 2 * sizeof (struct s));
      (*sp)->s_alloc = 2;
      (*sp)->s_used = 1;
      n = 0;
    }
  else
    {
      n = (*sp)->s_used++;
      if ((*sp)->s_alloc == n)
	{
	  (*sp)->s_alloc = n * 2;
	  (*sp) = ck_realloc ((*sp), sizeof (struct slops) + n * 2 * sizeof (struct s));
	}
    }
  (*sp)->s_b[n].row = r;
  (*sp)->s_b[n].clo = clo;
  (*sp)->s_b[n].chi = chi;
}

static void 
change_slop (VOIDSTAR where,
	     CELLREF r, CELLREF olo, CELLREF ohi, CELLREF lo, CELLREF hi)
{
  int n;
  struct slops *s;

  s = where;
  for (n = 0; n < s->s_used; n++)
    {
      if (s->s_b[n].row == r && s->s_b[n].clo == olo && s->s_b[n].chi == ohi)
	{
	  s->s_b[n].clo = lo;
	  s->s_b[n].chi = hi;
	  return;
	}
    }
}

static void 
_io_open_display (void)
{
  initscr ();
  scrollok (stdscr, 0);
#ifdef HAVE_CBREAK
  cbreak ();
#else
  crmode ();
#endif
  raw ();
  noecho ();
  nonl ();
  /* Must be after initscr() */
  io_init_windows (LINES, COLS, 1, 2, 1, 1, 1, 1);
  // io_init_windows (Global->scr_lines, Global->scr_cols, 1, 2, 1, 1, 1, 1);
  info_rows = 1;
  print_width = columns;		/* Make ascii print width == terminal width. */
}

void
cont_curses(void)
{
#ifdef HAVE_CBREAK
  cbreak ();
#else
  crmode ();
#endif
  raw ();
  noecho ();
  nonl ();
}


void
stop_curses(void)
{
#ifdef HAVE_CBREAK
  nocbreak ();
#else
  nocrmode ();
#endif
  noraw ();
  echo ();
  nl ();
  io_redisp ();
}

static void 
_io_cellize_cursor (void)
{
}

static void 
_io_inputize_cursor (void)
{
}

static void 
_io_redisp (void)
{
  if (!term_cursor_claimed)
    {
      _io_redraw_input ();
      if (!(input_view.current_info || input_active ||
	    input_view.expanded_keymap_prompt))
	move_cursor_to (cwin, curow, cucol, 0);
      else
	move ((input_view.current_info ? 0 : Global->input), 
	      input_view.prompt_wid + input_view.input_cursor -
	      input_view.visibility_begin); 
    }
  {
    struct rng * rng = &cwin->screen;
    if (   (curow > rng->hr)
	|| (curow < rng->lr)
	|| (cucol > rng->hc)
	|| (cucol < rng->lc))
      io_recenter_cur_win ();
  }
  refresh ();
}

static void 
_io_repaint_win (struct window *win)
{
  io_repaint ();
}

static void 
_io_repaint (void)
{
  CELLREF cc, rr;
  int n, n1;
  CELL *cp;
  struct window *win;

  clear ();
  io_fix_input ();
  redrew++;
  if (input_view.current_info)
    {
      redraw_info ();
      input_view.redraw_needed = FULL_REDRAW;
      _io_redraw_input ();
      return;
    }

  for (win = wins; win < &wins[nwin]; win++)
    {
      if (win->lh_wid)
	{
	  move (win->win_down - 1, win->win_over - win->lh_wid);
	  printw ("#%*d ", win->lh_wid - 2, 1 + win - wins);
	  if (win->flags & WIN_EDGE_REV)
	    standout ();
	  cc = win->screen.lc;
	  do
	    {
	      n = get_width (cc);
	      if (n > win->numc)
		n = win->numc;
	      if (n > 1)
		{
		  char *ptr;
		  char buf[30];

		  if (Global->a0)
		    ptr = col_to_str (cc);
		  else
		    {
		      sprintf (buf, "C%u", cc);
		      ptr = buf;
		    }
		  --n;
		  n1 = strlen (ptr);
		  if (n < n1)
		    printw ("%.*s ", n, "###############");
		  else
		    {
		      n1 = (n - n1) / 2;
		      printw ("%*s%-*s ", n1, "", n - n1, ptr);
		    }
		}
	      else if (n == 1)
		addstr ("#");
	    }
	  while (cc++ < win->screen.hc);

	  rr = win->screen.lr;
	  n = win->win_down;
	  do
	    {
	      n1 = get_height (rr);
	      if (n1)
		{
		  move (n, win->win_over - win->lh_wid);
		  if (Global->a0)
		    printw ("%-*d ", win->lh_wid - 1, rr);
		  else
		    printw ("R%-*d", win->lh_wid - 1, rr);
		  n += n1;
		}
	    }
	  while (rr++ < win->screen.hr);

	  if (win->flags & WIN_EDGE_REV)
	    standend ();
	}
      flush_slops (win->win_slops);
      find_cells_in_range (&(win->screen));
      while ((cp = next_row_col_in_range (&rr, &cc)))
	if (GET_TYP (cp))
	  io_pr_cell_win (win, rr, cc, cp);
    }
  if (!(cp = find_cell (curow, cucol)) || !GET_TYP (cp))
    io_display_cell_cursor ();
  input_view.redraw_needed = FULL_REDRAW;
  _io_redraw_input ();
  io_update_status ();
}

static void 
_io_close_display (int e)
{
	if (e == 0) {
		clear ();
		refresh ();
	}

	(void) endwin ();
}

static int 
_io_input_avail (void)
{
  return (FD_ISSET (0, &read_pending_fd_set)
	  || FD_ISSET (0, &exception_pending_fd_set));
}

static void 
_io_scan_for_input (int block)
{
  /* This function only exists because X kbd events don't generate
   * SIGIO. Under curses, the SIGIO hander does the work of this
   * function.
   * Attempt to have the curses mode be somewhat responsive even in
   * the presence of an endless loop by explicitly looking for events
   * here.
   */
  struct timeval tv;

  tv.tv_sec = 0;
  tv.tv_usec = 1000;
  block_until_excitement(&tv);
}

static void 
_io_wait_for_input (void)
{
  pause ();
}

static int 
_io_read_kbd (char *buf, int size)
{
  int r = read (0, buf, size);
  FD_CLR (0, &read_pending_fd_set);
  FD_CLR (0, &exception_pending_fd_set);
  return r;
}


#if defined(SIGIO)


static void 
_io_nodelay (int delayp)
{
  panic ("Trying to curses nodelay on a system with SIGIO.");
}

#else

static void 
_io_nodelay (int delayp)
{
  nodelay (stdscr, delayp);
}

#endif

static int 
_io_getch (void)
{
  char ch;
  return ((io_read_kbd (&ch, 1) != 1)
	  ? EOF
	  : ch);
}

static int 
_io_get_chr (char *prompt)
{
  int x;
  mvaddstr (Global->input, 0, prompt);
  clrtoeol ();
  Global->topclear = 2;
  refresh ();
  ++term_cursor_claimed;
  x = get_chr ();
  --term_cursor_claimed;
  return x;
}

#define BUFFER 10

static void 
_io_bell (void)
{
#ifndef HAVE_GETCAP
  putchar ('\007');
#else
  static char *vb;
  static int called = 0;

  if (!called)
    {
      called++;
      vb = getcap ("vb");
    }
  if (vb)
    {
      local_puts (vb);
    }
  else
    {
      local_putchar ('\007');
    }
#endif
}

static void
move_cursor_to (struct window *win, CELLREF r, CELLREF c, int dn)
{
  int cc;
  int cell_cursor_col;
  int rr;
  int cell_cursor_row;
  
  cell_cursor_col = win->win_over;
  for (cc = win->screen.lc; cc < c; cc++)
    cell_cursor_col += get_width (cc);
  cell_cursor_row = win->win_down + dn;
  for (rr = win->screen.lr; rr < r; rr++)
    cell_cursor_row += get_height (rr);
  move (cell_cursor_row, cell_cursor_col);
}

static void
_io_update_status (void)
{
  CELL *cp;
  char *dec;
  char *ptr;
  static char hmbuf[40];
  int wid;
  int plen;
  int dlen;
  int yy, xx;
  
  if (!user_status || input_view.current_info)
    return;
  getyx (stdscr, yy, xx);
  move (Global->status, 0);
  wid = columns - 2;
  
  if (mkrow != NON_ROW)
    {
      struct rng r;
      
      addch ('*');
      --wid;
      set_rng (&r, curow, cucol, mkrow, mkcol);
      ptr = range_name (&r);
    }
  else
    ptr = cell_name (curow, cucol);
  
  addstr (ptr);
  wid -= strlen (ptr);
  
  if (how_many != 1)
    {
      sprintf (hmbuf, " {%d}", how_many);
      addstr (hmbuf);
      wid -= strlen (hmbuf);
    }
  
  if ((cp = find_cell (curow, cucol)) && cp->cell_formula)
    {
      dec = decomp (curow, cucol, cp);
      dlen = strlen (dec);
    }
  else
    {
      dec = 0;
      dlen = 0;
    }
  
  ptr = cell_value_string (curow, cucol, 1);
  plen = strlen (ptr);
  
  if (dec)
    {
      wid -= 4;
      if (dlen + plen > wid)
	{
	  if (plen + 3 > wid)
	    printw (" %.*s... [...]", wid - 6, ptr);
	  else
	    printw (" %s [%.*s...]", ptr, wid - plen - 3, dec);
	}
      else
	printw (" %s [%s]", ptr, dec);
      decomp_free ();
    }
  else if (plen)
    {
      --wid;
      if (plen > wid)
	printw (" %.*s...", wid - 3, ptr);
      else
	printw (" %s", ptr);
    }
  
  clrtoeol ();
  move (yy, xx);
}

extern int auto_recalc;

static void
_io_clear_input_before (void)
{
  textout = 0;
  if (Global->topclear == 2)
    {
      move (Global->input, 0);
      clrtoeol ();
      Global->topclear = 0;
    }
  move (0, 0);
}

static void
_io_clear_input_after (void)
{
  if (Global->topclear)
    {
      move (Global->input, 0);
      clrtoeol ();
      Global->topclear = 0;
    }
}


static void
_io_pr_cell_win (struct window *win, CELLREF r, CELLREF c, CELL *cp)
{
  int glowing;
  int lenstr;
  int j;
  int wid, wwid;
  int hgt;
  char *ptr;
  int yy, xx;
  
  if (input_view.current_info)
    return;

  wid = get_width (c);
  if (!wid)
    return;
  if (wid > win->numc)
    wid = win->numc;
  hgt = get_height (r);
  if (!hgt)
    return;
  if (hgt > win->numr)
    hgt = win->numr;
  
  getyx (stdscr, yy, xx);
  glowing = (r == curow && c == cucol && win == cwin);
  ptr = print_cell (cp);
  move_cursor_to (win, r, c, 0);
  if (glowing)
    standout ();
  j = GET_JST (cp);
  if (j == JST_DEF)
    j = default_jst;
  lenstr = strlen (ptr);
  
  if (lenstr <= wid - 1)
    {
      CELLREF ccl, cch;
      
      if (j == JST_LFT)
	printw ("%-*.*s", wid, wid - 1, ptr);
      else if (j == JST_RGT)
	printw ("%*.*s ", wid - 1, wid - 1, ptr);
      else if (j == JST_CNT)
	{
	  wwid = (wid - 1) - lenstr;
	  printw ("%*s%*s ", (wwid + 1) / 2 + lenstr, ptr, wwid / 2, "");
	}
#ifdef TEST
      else
	panic ("Unknown justification");
#endif
      if (glowing)
	standend ();
      
      if (lenstr == 0 && c > win->screen.lc
	  && find_slop (win->win_slops, r, c - 1, &ccl, &cch))
	{
	  CELLREF ccdl, ccdh;
	  
	  if (find_slop (win->win_slops, r, c, &ccdl, &ccdh) && ccdl == c)
	    {
	      kill_slop (win->win_slops, r, ccdl, ccdh);
	      for (; ccdh != ccdl; --ccdh)
		if (ccdh != c && (wwid = get_width (ccdh)))
		  {
		    move_cursor_to (win, r, ccdh, 0);
		    printw ("%*s", wwid, "");
		  }
	    }
	  kill_slop (win->win_slops, r, ccl, cch);
	  io_pr_cell (r, ccl, find_cell (r, ccl));
	}
      else if (find_slop (win->win_slops, r, c, &ccl, &cch))
	{
	  kill_slop (win->win_slops, r, ccl, cch);
	  for (; cch != ccl; --cch)
	    if (cch != c && (wwid = get_width (cch)))
	      {
		move_cursor_to (win, r, cch, 0);
		printw ("%*s", wwid, "");
	      }
	  io_pr_cell (r, ccl, find_cell (r, ccl));
	}
    }
  else
    {
      CELLREF cc = c;
      CELL *ccp;
      CELLREF ccl, cch;
      
      for (wwid = wid; lenstr > wwid - 1; wwid += get_width (cc))
	{
	  if (++cc > win->screen.hc
	      || ((ccp = find_cell (r, cc))
		  && GET_TYP (ccp)
		  && (GET_FORMAT (ccp) != FMT_HID
		      || (GET_FORMAT (ccp) == FMT_DEF
			  && default_fmt != FMT_HID))))
	    {
	      --cc;
	      break;
	    }
	}
      
      if (lenstr > wwid - 1) {  /* FIXME: This construct needs to be checked */
	if (GET_TYP (cp) == TYP_FLT)
	  ptr = adjust_prc (ptr, cp, wwid - 1, wid - 1, j);
	else if (GET_TYP (cp) == TYP_INT)
	  ptr = (char *) numb_oflo;
      }
      
      if (wwid == 1)
	{
	  addch (' ');
	  if (glowing)
	    standend ();
	}
      else if (wwid == wid)
	{
	  printw ("%-*.*s ", wwid - 1, wwid - 1, ptr);
	  if (glowing)
	    standend ();
	}
      else if (glowing)
	{
	  printw ("%.*s", wid, ptr);
	  standend ();
	  printw ("%-*.*s ", wwid - wid - 1, wwid - wid - 1, ptr + wid);
	}
      else if (r == curow && (cucol > c && cucol <= cc))
	{
	  CELLREF ctmp;
	  int w_left;
	  int w_here;
	  
	  w_left = wid;
	  for (ctmp = c + 1; ctmp < cucol; ctmp++)
	    w_left += get_width (ctmp);
	  printw ("%.*s", w_left, ptr);
	  standout ();
	  w_here = get_width (cucol);
	  if (wwid > w_left + w_here)
	    {
	      printw ("%-*.*s", w_here, w_here, ptr + w_left);
	      standend ();
	      printw ("%-*.*s ",
		      wwid - (w_left + w_here) - 1, wwid - (w_left + w_here) - 1,
		      ptr + w_left + w_here);
	    }
	  else
	    {
	      printw ("%-*.*s", w_here, w_here - 1, ptr + w_left);
	      standend ();
	    }
	}
      else
	printw ("%-*.*s ", wwid - 1, wwid - 1, ptr);
      
      if (find_slop (win->win_slops, r, c, &ccl, &cch))
	{
	  change_slop (win->win_slops, r, ccl, cch, c, cc);
	  for (; cch > cc; --cch)
	    if ((wwid = get_width (cch)))
	      {
		move_cursor_to (win, r, cch, 0);
		printw ("%*s", wwid, "");
	      }
	  for (cch = c - 1; cch > ccl; --cch)
	    if ((wwid = get_width (cch)))
	      {
		move_cursor_to (win, r, cch, 0);
		printw ("%*s", wwid, "");
	      }
	  if (ccl != c)
	    io_pr_cell (r, ccl, find_cell (r, ccl));
	}
      else
	set_slop ((VOIDSTAR *) (&(win->win_slops)), r, c, cc);
    }
  if ((hgt > 1) && Global->display_formula_mode)
    {
      move_cursor_to (win, r, c, 1);
      ptr = decomp (r, c, cp);
      printw ("%.*s ", wid - 1, ptr);
      decomp_free ();
    }
  if (glowing)
    io_update_status ();
  move (yy, xx);
}


static void
_io_flush (void)
{
  refresh ();
}

void
_io_command_loop (int a)
{
	command_loop (a, 0);
}

void
tty_graphics (void)
{
  FD_SET (0, &read_fd_set);
  FD_SET (0, &exception_fd_set);
  io_command_loop = _io_command_loop;
  io_open_display = _io_open_display;
  io_redisp = _io_redisp;
  io_repaint = _io_repaint;
  io_repaint_win = _io_repaint_win;
  io_close_display = _io_close_display;
  io_input_avail = _io_input_avail;
  io_scan_for_input = _io_scan_for_input;
  io_wait_for_input = _io_wait_for_input;
  io_read_kbd = _io_read_kbd;
  io_nodelay = _io_nodelay;
  io_getch = _io_getch;
  io_bell = _io_bell;
  io_get_chr = _io_get_chr;
  io_update_status = _io_update_status;
  io_fix_input = _io_fix_input;
  io_move_cursor = _io_move_cursor;
  io_erase = _io_erase;
  io_insert = _io_insert;
  io_over = _io_over;
  io_flush = _io_flush;
  io_clear_input_before = _io_clear_input_before;
  io_clear_input_after = _io_clear_input_after;
  io_pr_cell_win = _io_pr_cell_win;
  io_hide_cell_cursor = _io_hide_cell_cursor;
  io_cellize_cursor = _io_cellize_cursor;
  io_inputize_cursor = _io_inputize_cursor;
  io_display_cell_cursor = _io_display_cell_cursor;
}


syntax highlighted by Code2HTML, v. 0.9.1