/****************************************************************************
**
*W  sysfiles.h                  GAP source                       Frank Celler
*W                                                         & Martin Schönert
*W                                                  & Burkhard Höfling (MAC)
**
**
*Y  Copyright (C)  1996,  Lehrstuhl D für Mathematik,  RWTH Aachen,  Germany
*Y  (C) 1998 School Math and Comp. Sci., University of St Andrews, Scotland
*Y  Copyright (C) 2002 The GAP Group
**
**  The  file 'system.c'  declares  all operating system  dependent functions
**  except file/stream handling which is done in "sysfiles.h".
*/

#ifndef libGAP_GAP_SYSFILES_H
#define libGAP_GAP_SYSFILES_H


#include <stdio.h>


/****************************************************************************
**


*F * * * * * * * * * * * * * * dynamic loading  * * * * * * * * * * * * * * *
*/


/****************************************************************************
**
*F  SyFindOrLinkGapRootFile( <filename>, <crc>, <res> ) . . . .  load or link
**
**  'SyFindOrLinkGapRootFile'  tries to find a GAP  file in the root area and
**  check  if   there is a corresponding    statically  or dynamically linked
**  module.  If the CRC matches this module  is loaded otherwise the filename
**  is returned.
**
**  The function returns:
**
**  0: no file or module was found
**  1: if a dynamically linked module was found
**  2: if a statically linked module was found
**  3: a GAP file was found
**  4: a GAP file was found and the CRC value didn't match
*/

typedef union {
  libGAP_Char pathname[256];
  libGAP_StructInitInfo * module_info;
} libGAP_TypGRF_Data;

extern libGAP_Int libGAP_SyFindOrLinkGapRootFile (
            const libGAP_Char *    filename,
            libGAP_Int4            crc_gap,
            libGAP_TypGRF_Data *   result );


/****************************************************************************
**
*F  SyGAPCRC( <name> )  . . . . . . . . . . . . . . . . . . crc of a GAP file
**
**  This function should  be clever and handle  white spaces and comments but
**  one has to certain that such characters are not ignored in strings.
*/
extern libGAP_Int4 libGAP_SyGAPCRC(
            const libGAP_Char *    name );


/****************************************************************************
**
*F  SyLoadModule( <name> )  . . . . . . . . . . . . .  load a compiled module
*/
extern libGAP_InitInfoFunc libGAP_SyLoadModule(
            const libGAP_Char *    name );


/****************************************************************************
**

*F * * * * * * * * * * * * * * * window handler * * * * * * * * * * * * * * *
*/


/****************************************************************************
**
*F  syWinPut( <fid>, <cmd>, <str> ) . . . . send a line to the window handler
**
**  'syWinPut'  send the command   <cmd> and the  string  <str> to the window
**  handler associated with the  file identifier <fid>.   In the string <str>
**  '@'  characters are duplicated, and   control characters are converted to
**  '@<chr>', e.g., <newline> is converted to '@J'.
*/
extern void libGAP_syWinPut (
            libGAP_Int                 fid,
            const libGAP_Char *    cmd,
            const libGAP_Char *    str );


/****************************************************************************
**
*F  SyWinCmd( <str>, <len> )  . . . . . . . . . . . .  . execute a window cmd
**
**  'SyWinCmd' send   the  command <str> to  the   window  handler (<len>  is
**  ignored).  In the string <str> '@' characters are duplicated, and control
**  characters  are converted to  '@<chr>', e.g.,  <newline> is converted  to
**  '@J'.  Then  'SyWinCmd' waits for  the window handlers answer and returns
**  that string.
*/
extern libGAP_Char * libGAP_SyWinCmd (
            const libGAP_Char *    str,
            libGAP_UInt                len );


/****************************************************************************
**


*F * * * * * * * * * * * * * * * * open/close * * * * * * * * * * * * * * * *
*/


/****************************************************************************
**
*V  syBuf . . . . . . . . . . . . . .  buffer and other info for files, local
**
**  'syBuf' is  a array used as  buffers for  file I/O to   prevent the C I/O
**  routines  from   allocating their  buffers  using  'malloc',  which would
**  otherwise confuse Gasman.
*/
typedef struct {
  int         fp;          /* file descriptor for this file */
  int         echo;        /* file descriptor for the echo */
  libGAP_UInt        pipe;        /* file is really a pipe */
  FILE       *pipehandle;  /* for pipes we need to remember the file handle */
  libGAP_UInt        ateof;       /* set to 1 by any read operation that hits eof
                              reset to 0 by a subsequent successful read */
  libGAP_UInt        crlast;      /* records that last character read was \r for
                              cygwin and othger systems that need end-of-line
                              hackery */
  libGAP_Int         bufno;       /* if non-negative then this file has a buffer in
                              syBuffers[bufno]; If negative, this file may not
                              be buffered */
  libGAP_UInt        isTTY;       /* set in Fopen when this fid is a *stdin* or *errin*
                              and really is a tty*/
} libGAP_SYS_SY_BUF;

#define libGAP_SYS_FILE_BUF_SIZE 20000

typedef struct {
  libGAP_Char buf[libGAP_SYS_FILE_BUF_SIZE];
  libGAP_UInt inuse;
  libGAP_UInt bufstart;
  libGAP_UInt buflen;
} libGAP_SYS_SY_BUFFER;

extern libGAP_SYS_SY_BUF libGAP_syBuf [256];

extern libGAP_SYS_SY_BUFFER libGAP_syBuffers[32];

extern libGAP_UInt libGAP_SySetBuffering( libGAP_UInt fid );

/****************************************************************************
**
*F  SyFileno( <fid> ) . . . . . . . . . . . . . . get operating system fileno
*/
#define libGAP_SyFileno(fid)   (fid==-1?-1:libGAP_syBuf[fid].fp)


/****************************************************************************
**
*F  SyFopen( <name>, <mode> ) . . . . . . . .  open the file with name <name>
**
**  The function 'SyFopen'  is called to open the file with the name  <name>.
**  If <mode> is "r" it is opened for reading, in this case  it  must  exist.
**  If <mode> is "w" it is opened for writing, it is created  if  neccessary.
**  If <mode> is "a" it is opened for appending, i.e., it is  not  truncated.
**
**  'SyFopen' returns an integer used by the scanner to  identify  the  file.
**  'SyFopen' returns -1 if it cannot open the file.
**
**  The following standard files names and file identifiers  are  guaranteed:
**  'SyFopen( "*stdin*", "r")' returns 0 identifying the standard input file.
**  'SyFopen( "*stdout*","w")' returns 1 identifying the standard outpt file.
**  'SyFopen( "*errin*", "r")' returns 2 identifying the brk loop input file.
**  'SyFopen( "*errout*","w")' returns 3 identifying the error messages file.
**
**  If it is necessary to adjust the  filename  this  should  be  done  here.
**  Right now GAP does not read nonascii files, but if this changes sometimes
**  'SyFopen' must adjust the mode argument to open the file in binary  mode.
*/
extern libGAP_Int libGAP_SyFopen (
            const libGAP_Char *        name,
            const libGAP_Char *        mode );


/****************************************************************************
**
*F  SyFclose( <fid> ) . . . . . . . . . . . . . . . . .  close the file <fid>
**
**  'SyFclose' closes the file with the identifier <fid>  which  is  obtained
**  from 'SyFopen'.
*/
extern libGAP_Int libGAP_SyFclose (
            libGAP_Int                 fid );


/****************************************************************************
**
*F  SyIsEndOfFile( <fid> )  . . . . . . . . . . . . . . . end of file reached
*/
extern libGAP_Int libGAP_SyIsEndOfFile (
    libGAP_Int                 fid );


/****************************************************************************
**
*F  SyFgets( <line>, <lenght>, <fid> )  . . . . .  get a line from file <fid>
**
**  'SyFgets' is called to read a line from the file  with  identifier <fid>.
**  'SyFgets' (like 'fgets') reads characters until either  <length>-1  chars
**  have been read or until a <newline> or an  <eof> character is encoutered.
**  It retains the '\n' (unlike 'gets'), if any, and appends '\0' to  <line>.
**  'SyFgets' returns <line> if any char has been read, otherwise '(char*)0'.
**
**  'SyFgets'  allows to edit  the input line if the  file  <fid> refers to a
**  terminal with the following commands:
**
**      <ctr>-A move the cursor to the beginning of the line.
**      <esc>-B move the cursor to the beginning of the previous word.
**      <ctr>-B move the cursor backward one character.
**      <ctr>-F move the cursor forward  one character.
**      <esc>-F move the cursor to the end of the next word.
**      <ctr>-E move the cursor to the end of the line.
**
**      <ctr>-H, <del> delete the character left of the cursor.
**      <ctr>-D delete the character under the cursor.
**      <ctr>-K delete up to the end of the line.
**      <esc>-D delete forward to the end of the next word.
**      <esc>-<del> delete backward to the beginning of the last word.
**      <ctr>-X delete entire input line, and discard all pending input.
**      <ctr>-Y insert (yank) a just killed text.
**
**      <ctr>-T exchange (twiddle) current and previous character.
**      <esc>-U uppercase next word.
**      <esc>-L lowercase next word.
**      <esc>-C capitalize next word.
**
**      <tab>   complete the identifier before the cursor.
**      <ctr>-L insert last input line before current character.
**      <ctr>-P redisplay the last input line, another <ctr>-P will redisplay
**              the line before that, etc.  If the cursor is not in the first
**              column only the lines starting with the string to the left of
**              the cursor are taken. The history is limitied to ~8000 chars.
**      <ctr>-N Like <ctr>-P but goes the other way round through the history
**      <esc>-< goes to the beginning of the history.
**      <esc>-> goes to the end of the history.
**      <ctr>-O accept this line and perform a <ctr>-N.
**
**      <ctr>-V enter next character literally.
**      <ctr>-U execute the next command 4 times.
**      <esc>-<num> execute the next command <num> times.
**      <esc>-<ctr>-L repaint input line.
**
**  Not yet implemented commands:
**
**      <ctr>-S search interactive for a string forward.
**      <ctr>-R search interactive for a string backward.
**      <esc>-Y replace yanked string with previously killed text.
**      <ctr>-_ undo a command.
**      <esc>-T exchange two words.
*/
#if HAVE_SELECT
extern libGAP_Obj libGAP_OnCharReadHookActive;  /* if bound the hook is active */
extern libGAP_Obj libGAP_OnCharReadHookInFds;   /* a list of UNIX file descriptors */
extern libGAP_Obj libGAP_OnCharReadHookInFuncs; /* a list of GAP functions */
extern libGAP_Obj libGAP_OnCharReadHookOutFds;  /* a list of UNIX file descriptors */
extern libGAP_Obj libGAP_OnCharReadHookOutFuncs;/* a list of GAP functions with 0 args */
extern libGAP_Obj libGAP_OnCharReadHookExcFds;  /* a list of UNIX file descriptors */
extern libGAP_Obj libGAP_OnCharReadHookExcFuncs;/* a list of GAP functions with 0 args */
#endif

extern libGAP_Char * libGAP_SyFgets (
            libGAP_Char *              line,
            libGAP_UInt                length,
            libGAP_Int                 fid );


/****************************************************************************
**
*F  SyFputs( <line>, <fid> )  . . . . . . . .  write a line to the file <fid>
**
**  'SyFputs' is called to put the  <line>  to the file identified  by <fid>.
*/
extern void libGAP_SyFputs (
            const libGAP_Char *        line,
            libGAP_Int                 fid );


/****************************************************************************
**
*F  SyIsIntr()  . . . . . . . . . . . . . . . . check wether user hit <ctr>-C
**
**  'SyIsIntr' is called from the evaluator at  regular  intervals  to  check
**  wether the user hit '<ctr>-C' to interrupt a computation.
**
**  'SyIsIntr' returns 1 if the user typed '<ctr>-C' and 0 otherwise.
*/
extern void libGAP_SyInstallAnswerIntr ( void );

extern libGAP_UInt libGAP_SyIsIntr ( void );


/****************************************************************************
**

*F * * * * * * * * * * * * * * * * * output * * * * * * * * * * * * * * * * *
*/


/****************************************************************************
**

*F  SyEchoch( <ch>, <fid> ) . . . . . . . . . . . echo a char to <fid>, local
*/
extern libGAP_Int libGAP_SyEchoch (
    libGAP_Int                 ch,
    libGAP_Int                 fid );


/****************************************************************************
**

*F * * * * * * * * * * * * * * * * * input  * * * * * * * * * * * * * * * * *
*/


/****************************************************************************
**

*F  SyFtell( <fid> )  . . . . . . . . . . . . . . . . . .  position of stream
*/
extern libGAP_Int libGAP_SyFtell (
    libGAP_Int                 fid );


/****************************************************************************
**
*F  SyFseek( <fid>, <pos> )   . . . . . . . . . . . seek a position of stream
*/
extern libGAP_Int libGAP_SyFseek (
    libGAP_Int                 fid,
    libGAP_Int                 pos );


/****************************************************************************
**
*F  SyGetch( <fid> )  . . . . . . . . . . . . . . . . . get a char from <fid>
**
**  'SyGetch' reads a character from <fid>, which is switch to raw mode if it
**  is *stdin* or *errin*.
*/
extern libGAP_Int libGAP_SyGetch (
    libGAP_Int                 fid );


/****************************************************************************
**
*F  SyGetc( <fid> ).  . . . . . . . . . . . . . . . . . get a char from <fid>
**
**  'SyGetc' reads a character from <fid>, without any translation or
**   interference
*/

extern libGAP_Int libGAP_SyGetc
(
    libGAP_Int                 fid );

/****************************************************************************
**
*F  SyPutc( <fid>, <char> ).. . . . . . . . . . . . . . . put a char to <fid>
**
**  'SyPutc' writes a character to <fid>, without any translation or
**   interference
*/

extern libGAP_Int libGAP_SyPutc
(
    libGAP_Int                 fid,
    libGAP_Char                c );


/****************************************************************************
**

*F * * * * * * * * * * * * system error messages  * * * * * * * * * * * * * *
*/


/****************************************************************************
**
*V  SyLastMacErrorNo . . . . . . . . . . . . . .last error number, Macintosh
*/


/****************************************************************************
**
*V  SyLastErrorNo . . . . . . . . . . . . . . . . . . . . . last error number
*/
extern libGAP_Int libGAP_SyLastErrorNo;


/****************************************************************************
**
*V  SyLastErrorMessage  . . . . . . . . . . . . . . . . .  last error message
*/
extern libGAP_Char libGAP_SyLastErrorMessage [ 1024 ];


/****************************************************************************
**
*F  SyClearErrorNo()  . . . . . . . . . . . . . . . . .  clear error messages
*/
extern void libGAP_SyClearErrorNo ( void );


/****************************************************************************
**
*F  SySetErrorNo()  . . . . . . . . . . . . . . . . . . . . set error message
*/
extern void libGAP_SySetErrorNo ( void );


/****************************************************************************
**

*F * * * * * * * * * * * * * file and execution * * * * * * * * * * * * * * *
*/

/****************************************************************************
**
*F  SyExecuteProcess( <dir>, <prg>, <in>, <out>, <args> ) . . . . new process
**
**  Start  <prg> in  directory <dir>  with  standard input connected to <in>,
**  standard  output  connected to <out>   and arguments.  No  path search is
**  performed, the return  value of the process  is returned if the operation
**  system supports such a concept.
*/
extern libGAP_UInt libGAP_SyExecuteProcess (
    libGAP_Char *                  dir,
    libGAP_Char *                  prg,
    libGAP_Int                     in,
    libGAP_Int                     out,
    libGAP_Char *                  args[] );


/****************************************************************************
**
*F  SyIsExistingFile( <name> )  . . . . . . . . . . . does file <name> exists
**
**  'SyIsExistingFile' returns 1 if the  file <name> exists and 0  otherwise.
**  It does not check if the file is readable, writable or excuteable. <name>
**  is a system dependent description of the file.
*/
extern libGAP_Int libGAP_SyIsExistingFile(
            const libGAP_Char * name );


/****************************************************************************
**
*F  SyIsReadableFile( <name> )  . . . . . . . . . . . is file <name> readable
**
**  'SyIsReadableFile'   returns 1  if the   file  <name> is   readable and 0
**  otherwise. <name> is a system dependent description of the file.
*/
extern libGAP_Int libGAP_SyIsReadableFile(
            const libGAP_Char * name );


/****************************************************************************
**
*F  SyIsWritable( <name> )  . . . . . . . . . . . is the file <name> writable
**
**  'SyIsWriteableFile'   returns 1  if the  file  <name>  is  writable and 0
**  otherwise. <name> is a system dependent description of the file.
*/
extern libGAP_Int libGAP_SyIsWritableFile(
            const libGAP_Char * name );


/****************************************************************************
**
*F  SyIsExecutableFile( <name> )  . . . . . . . . . is file <name> executable
**
**  'SyIsExecutableFile' returns 1 if the  file <name>  is  executable and  0
**  otherwise. <name> is a system dependent description of the file.
*/
extern libGAP_Int libGAP_SyIsExecutableFile(
            const libGAP_Char * name );


/****************************************************************************
**
*F  SyIsDirectoryPath( <name> ) . . . . . . . . .  is file <name> a directory
**
**  'SyIsDirectoryPath' returns 1 if the  file <name>  is a directory  and  0
**  otherwise. <name> is a system dependent description of the file.
*/
extern libGAP_Int libGAP_SyIsDirectoryPath (
            const libGAP_Char * name );


/****************************************************************************
**
*F  SyRemoveFile( <name> )  . . . . . . . . . . . . . . .  remove file <name>
*/
extern libGAP_Int libGAP_SyRemoveFile (
            const libGAP_Char * name );

/****************************************************************************
**
*F  SyMkDir( <name> )  . . . . . . . . . . . . . . .  remove file <name>
*/
extern libGAP_Int libGAP_SyMkdir (
            const libGAP_Char * name );

/****************************************************************************
**
*F  SyRmdir( <name> )  . . . . . . . . . . . . . . .  remove directory <name>
*/
extern libGAP_Int libGAP_SyRmdir (
            const libGAP_Char * name );

/****************************************************************************
**
*F  SyIsDir( <name> )  . . . . . . . . . . . . .  test if something is a dir
**
**  Returns 'F' for a regular file, 'L' for a symbolic link and 'D'
**  for a real directory, 'C' for a character device, 'B' for a block
**  device 'P' for a FIFO (named pipe) and 'S' for a socket.
*/
extern libGAP_Obj libGAP_SyIsDir (
            const libGAP_Char * name );

/****************************************************************************
**
*F  SyFindGapRootFile( <filename> ) . . . . . . . .  find file in system area
*/
extern libGAP_Char * libGAP_SyFindGapRootFile (
            const libGAP_Char *    filename );


/****************************************************************************
**

*F * * * * * * * * * * * * * * * directories  * * * * * * * * * * * * * * * *
*/


/****************************************************************************
**
*F  SyTmpname() . . . . . . . . . . . . . . . . . return a temporary filename
**
**  'SyTmpname' creates and returns a new temporary name.
*/
extern libGAP_Char * libGAP_SyTmpname ( void );


/****************************************************************************
**
*F  SyTmpdir( <hint> )  . . . . . . . . . . . .  return a temporary directory
**
**  'SyTmpdir'  returns the directory   for  a temporary directory.  This  is
**  guaranteed  to be newly  created and empty  immediately after the call to
**  'SyTmpdir'. <hint> should be used by 'SyTmpdir' to  construct the name of
**  the directory (but 'SyTmpdir' is free to use only  a part of <hint>), and
**  must be a string of at most 8 alphanumerical characters.  Under UNIX this
**  would   usually   represent   '/usr/tmp/<hint>_<proc_id>_<cnt>/',   e.g.,
**  '/usr/tmp/guava_17188_1/'.
*/
extern libGAP_Char * libGAP_SyTmpdir ( const libGAP_Char * hint );

/****************************************************************************
**
*F  void getwindowsize( void )  . probe the OS for the window size and
**                               set SyNrRows and SyNrCols accordingly
*/

extern void libGAP_getwindowsize( void );

extern void     libGAP_InterruptExecStat ( void );

/***************************************************************************
**
*F HasAvailableBytes( <fid> ) returns positive if  a subsequent read to <fid>
**                            will read at least one byte without blocking
*/
extern libGAP_Int libGAP_HasAvailableBytes( libGAP_UInt fid );

extern libGAP_Char *libGAP_SyFgetsSemiBlock ( 
    libGAP_Char *              line,
    libGAP_UInt                length,
    libGAP_Int                 fid);

/***************************************************************************
**
*F SyWinPut( <fid>, <cmd>, <str> ) . . . . send a line to the window handler
**
**  'syWinPut'  send the command   <cmd> and the  string  <str> to the window
**  handler associated with the  file identifier <fid>.   In the string <str>
**  '@'  characters are duplicated, and   control characters are converted to
**  '@<chr>', e.g., <newline> is converted to '@J'.
*/

extern void libGAP_syWinPut (
    libGAP_Int                 fid,
    const libGAP_Char *        cmd,
    const libGAP_Char *        str );


     
/****************************************************************************
**

*F * * * * * * * * * * * * * initialize package * * * * * * * * * * * * * * *
*/

/****************************************************************************
**

*F  InitInfoSysFiles()  . . . . . . . . . . . . . . . table of init functions
*/
libGAP_StructInitInfo * libGAP_InitInfoSysFiles ( void );


#endif // GAP_SYSFILES_H

/****************************************************************************
**

*E  sysfiles.h  . . . . . . . . . . . . . . . . . . . . . . . . . . ends here
*/
