/*-------------------------------------------------------------------------*/
/* GNU Prolog                                                              */
/*                                                                         */
/* Part  : line-edit library                                               */
/* File  : stty.c                                                          */
/* Descr.: TTY features                                                    */
/* Author: Daniel Diaz                                                     */
/*                                                                         */
/* Copyright (C) 1999,2000 Daniel Diaz                                     */
/*                                                                         */
/* GNU Prolog 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 any later version.       */
/*                                                                         */
/* GNU Prolog 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 program; if not, write to the Free Software Foundation, Inc.  */
/* 59 Temple Place - Suite 330, Boston, MA 02111, USA.                     */
/*-------------------------------------------------------------------------*/
#include "../EnginePl/gp_config.h"

#include <stdio.h>
#include <signal.h>

#if defined(__unix__) || defined(__CYGWIN__)

#if defined(HAVE_SYS_IOCTL_COMPAT_H)
#include <sys/ioctl_compat.h>
#endif

#include <unistd.h>

#if defined(sun) /* && defined(sparc) */ /* commented out for ix86/solaris */

#include <sys/filio.h>
int ioctl(int d, int request, ...);

#else

#include <sys/ioctl.h>

#endif

#if defined(HAVE_TERMIO_H)
#include <termio.h>
typedef struct termio TermIO;
#define GETIOP TCGETA
#define SETIOP TCSETA
#elif defined(HAVE_TERMIOS_H)
#include <termios.h>
typedef struct termios TermIO;
#define GETIOP TIOCGETP
#define SETIOP TIOCSETP
#endif

#elif defined(_WIN32) && !defined(__CYGWIN__)

#include <conio.h>

#endif




#define STTY_FILE
#include "stty.h"
#include "char_io.h"
#include "linedit.h"




/*---------------------------------*/
/* Constants                       */
/*---------------------------------*/

/*---------------------------------*/
/* Type Definitions                */
/*---------------------------------*/

/*---------------------------------*/
/* Global Variables                */
/*---------------------------------*/

#if defined(__unix__) || defined(__CYGWIN__)

static int    is_tty_in;
static int    is_tty_out;
static TermIO old_stty_in;
static TermIO new_stty_in;
static TermIO old_stty_out;
static TermIO new_stty_out;

#elif defined(_WIN32)

static DWORD         im;

#endif


static int           interrupt_key;




/*---------------------------------*/
/* Function Prototypes             */
/*---------------------------------*/


#if defined(__unix__) || defined(__CYGWIN__)

static
void      Set_TTY_Mode          (TermIO *old,TermIO *new);

#define Gtty(fd,s) ioctl(fd,GETIOP,s)
#define Stty(fd,s) ioctl(fd,SETIOP,s)

#endif




/*-------------------------------------------------------------------------*/
/* LE_INIT                                                                 */
/*                                                                         */
/* Mode cbreak (raw mode).                                                 */
/*-------------------------------------------------------------------------*/
void LE_Init(int fd_in,int fd_out)

{
#if defined(__unix__) || defined(__CYGWIN__)
 is_tty_in= !Gtty(fd_in,&old_stty_in);
 is_tty_out=!Gtty(fd_out,&old_stty_out);

 if (is_tty_in)
    {
     interrupt_key=old_stty_in.c_cc[VINTR];
     Set_TTY_Mode(&old_stty_in,&new_stty_in);
     Stty(fd_in,&new_stty_in);
    }
  else
     interrupt_key=KEY_CTRL('C');

 if (is_tty_out)
    {
     Set_TTY_Mode(&old_stty_out,&new_stty_out);
     Stty(fd_out,&new_stty_out);
    }
 fflush(stdout);
 fflush(stderr);


#elif defined(_WIN32)

 if (!w32gc_present)
    {
     h_stdin =GetStdHandle(STD_INPUT_HANDLE);
     h_stdout=GetStdHandle(STD_OUTPUT_HANDLE);
     GetConsoleMode(h_stdin,&im); 
     SetConsoleMode(h_stdin,im & ~ENABLE_PROCESSED_INPUT);
     fflush(stdout);
     fflush(stderr);
    }

 interrupt_key=KEY_CTRL('C');                 /* WIN32: interrupt = CTRL+C */
 
#endif
}




/*-------------------------------------------------------------------------*/
/* LE_TERM                                                                 */
/*                                                                         */
/* Restore initial mode (cooked mode).                                     */
/*-------------------------------------------------------------------------*/
void LE_Term(int fd_in,int fd_out)

{
#if defined(__unix__) || defined(__CYGWIN__)

 if (is_tty_in)
     Stty(fd_in,&old_stty_in);

 if (is_tty_out)
     Stty(fd_out,&old_stty_out);

#elif defined(_WIN32)

 if (!w32gc_present)
     SetConsoleMode(h_stdin,im);

#endif
}




/*-------------------------------------------------------------------------*/
/* LE_SCREEN_SIZE                                                          */
/*                                                                         */
/*-------------------------------------------------------------------------*/
void LE_Screen_Size(int fd_out,int *row,int *col)

{
#if defined(__unix__) || defined(__CYGWIN__)
 struct winsize ws;

 if (!is_tty_out)
    {
     row=col=0;
     return;
    }

 ioctl(fd_out,TIOCGWINSZ,&ws);
 *row=ws.ws_row;
 *col=ws.ws_col;

#elif defined(_WIN32)

 if (w32gc_screen_size)
     (*w32gc_screen_size)(row,col);
  else
    {
     CONSOLE_SCREEN_BUFFER_INFO csbi; 
 
     if (GetConsoleScreenBufferInfo(h_stdout,&csbi))
        {
         *row=csbi.dwSize.Y; 
         *col=csbi.dwSize.X; 
        }
      else
        {
         *row=25;
         *col=80;
        }
    }

#endif
}




/*-------------------------------------------------------------------------*/
/* LE_WHICH_SIGNAL                                                         */
/*                                                                         */
/*-------------------------------------------------------------------------*/
int LE_Which_Signal(int c)

{
 if (c==interrupt_key)
     return SIGINT;

 return 0;
}




/*-------------------------------------------------------------------------*/
/* LE_KBD_IS_NOT_EMPTY                                                     */
/*                                                                         */
/*-------------------------------------------------------------------------*/
int LE_Kbd_Is_Not_Empty(int fd_in)

{
#if defined(__unix__)

#ifdef FIONREAD
 int nb_not_read;
 ioctl(0,FIONREAD,&nb_not_read);
 return nb_not_read!=0;
#else /* SCO */
 return 0;
#endif

#elif defined(__CYGWIN__)

 return 0;


#elif defined(_WIN32)

 if (w32gc_kbd_is_not_empty)
     return (*w32gc_kbd_is_not_empty)();
  else
     return _kbhit();

#endif
}




#if defined(__unix__) || defined(__CYGWIN__)

/*-------------------------------------------------------------------------*/
/* SET_TTY_MODE                                                            */
/*                                                                         */
/* Mode cbreak (raw mode).                                                 */
/*-------------------------------------------------------------------------*/
static void Set_TTY_Mode(TermIO *old,TermIO *new)

{
 *new = *old;

 new->c_iflag &= ~(INLCR|IGNCR|ICRNL|IXON|IXOFF);
 new->c_oflag =  OPOST | ONLCR;
 new->c_lflag &= ~(ICANON|ECHO|ECHONL);

 new->c_cc[VMIN]=1;                                      /* MIN # of chars */
 new->c_cc[VTIME]=1;                                               /* TIME */

 new->c_cc[VINTR]=-1;                         /* desactivate SIGINT signal */
}

#endif
