/****************************************************************************
**
*A  system.c                    GAP source                   Martin Schoenert
*A                                                      & Frank Celler (MACH)
*A                                                    & Steve Linton (MS-DOS)
*A                                                  & Harald Boegeholz (OS/2)
*A                                                         & Paul Doyle (VMS)
*A                                                         & Dave Bayer (MAC)
*A                                                  & Burkhard Hoefling (MAC)
**
*H  @(#)$Id: system.c,v 3.5.1.5 1995/05/18 12:54:49 mschoene Rel $
**
*Y  Copyright (C)  1993,  Lehrstuhl D fuer Mathematik,  RWTH Aachen,  Germany
**
**  The file 'system.c' contains  all  operating system dependent  functions.
**  The following labels determine which operating system is actually used.
**
**  SYS_IS_BSD
**      For  Berkeley UNIX systems, such as  4.2 BSD,  4.3 BSD,  free 386BSD,
**      and DEC's Ultrix.
**
**  SYS_IS_USG
**      For System V UNIX systems, such as SUN's SunOS 4.0, Hewlett Packard's
**      HP-UX, Masscomp's RTU, free Linux, and MIPS Risc/OS.
**
**  SYS_IS_MACH
**      For Mach derived systems, such as NeXT's NextStep.
**
**  SYS_IS_OS2_EMX
**      For OS/2 2.x and DOS with the EMX port of the GNU C compiler.
**
**  SYS_IS_MSDOS_DJGPP
**      For MS-DOS with Delories port of the GNU C compiler.
**
**  SYS_IS_TOS_GCC2
**      For Atari's TOS with the port of the GNU C compiler.
**
**  SYS_IS_VMS
**      For DEC's VMS 5.0 or later with the VAX C compiler 3.0 or later.
**
**  SYS_IS_MAC_MPW
**      For Apple's Macintosh with the Mac Programmers Workshop compiler.
**
**  SYS_IS_MAC_SYC
**      For  Apple's  Macintosh  with the  Symantec C++ 7.0 (or  Think C 6.0)
**      compiler.
**
**  Also the file contains prototypes for all the system calls and/or library
**  function used as defined in  ``Harbison & Steele, A C Reference Manual''.
**
**  If there is  a prototype in an  include file and it  does not  agree with
**  this one, then the compiler will signal an  error or warning, and you can
**  manually check whether the incompatibility is critical or quite harmless.
**  If there is a prototype in  an include file and it  agrees with this one,
**  then the compiler will be silent.  If there is no prototype in an include
**  file, the compiler cannot check, but then the prototype does no harm.
**
**  Unfortunately  there can be some incompatibilities with the prototypes in
**  the  include files.  To overcome this  difficulties  it  is  possible  to
**  change  or undefine  the prototypes  with  the  following  symbols.  They
**  should be added to the 'Makefile' if neccessary.
**
**  SYS_HAS_ANSI=<ansi>
**      Some functions have different prototypes in  ANSI and  traditional C.
**      For compilers that are  ANSI  the default uses the  ANSI  prototypes,
**      and you use the  traditional prototypes by defining 'SYS_HAS_ANSI=0'.
**      For  non ANSI compilers the default uses the  traditional prototypes,
**      and you can use the ANSI prototypes by defining 'SYS_HAS_ANSI=1'.
**
**  SYS_HAS_CONST=<const_q>
**      Some  functions do  not modifiy  some of  their  arguments,  and have
**      thus  'const' qualifiers  for those  arguments  in their  prototypes.
**      For compilers that are  ANSI the default uses the  const  qualifiers,
**      and you can remove the const qualifiers by defining 'SYS_HAS_CONST='.
**      For compilers that are  not ANSI  the default does not use the  const
**      qualifiers and you can use them by defining 'SYS_HAS_CONST=const'.
**
**  SYS_HAS_SIG_T=<sig_t>
**      Use this to define the type of the value returned by signal handlers.
**      This should be either 'void' (default, ANSI C) or 'int' (older UNIX).
**
**  SYS_HAS_STDIO_PROTO
**      Use this to undefine the prototypes for 'fopen', 'fclose',  'setbuf',
**      'fgets', 'fputs', 'read', and 'write'.
**
**  SYS_HAS_READ_PROTO
**      Use this to undefine the prototypes for 'read' and 'write'.
**
**  SYS_HAS_STRING_PROTO
**      Use this to undefine the  prototypes  for  'strncat',  'strcmp',  and
**      'strlen'.
**
**  SYS_HAS_IOCTL_PROTO
**      Use this to undefine the prototype for 'ioctl'.
**
**  SYS_HAS_SIGNAL_PROTO
**      Use this to undefine  the  prototypes  for  'signal',  'getpid',  and
**      'kill'.
**
**  SYS_HAS_TIME_PROTO
**      Use this to undefine the prototypes for 'time', 'times', and
**      'getrusage'.
**
**  SYS_HAS_MALLOC_PROTO
**      Use this to undefine the prototypes for 'malloc' and 'free'.
**
**  SYS_HAS_MISC_PROTO
**      Use this to undefine the prototypes for 'exit',  'system',  'tmpnam',
**      'sbrk', 'getenv', 'atoi', 'isatty', and 'ttyname'.
**
**  SYS_HAS_BROKEN_STRNCAT
**      Use this if your 'strncat' is broken.  At least in SCO ODT2.0
**      (SVR3.2) 'strncat' has problems if the len is a multiple of 4.
**
*H  $Log: system.c,v $
*H  Revision 3.5.1.5  1995/05/18  12:54:49  mschoene
*H  fixed 'SyHelp', manual now has more than 64 chapters
*H
*H  Revision 3.5.1.4  1995/05/18  03:23:21  mschoene
*H  added Macintosh support by Burkhard Hoefling
*H
*H  Revision 3.5.1.3  1995/05/11  14:52:23  mschoene
*H  fixed 'SyHelp' to tolerate funny table of contents lines
*H
*H  Revision 3.5.1.2  1994/09/07  07:08:50  fceller
*H  added SYS_HAS_BROKEN_STRNCAT
*H
*H  Revision 3.5.1.1  1994/09/06  10:15:02  fceller
*H  added '-r' option to avoid reading of the .gaprc file
*H
*H  Revision 3.5  1993/12/17  07:26:32  mschoene
*H  changed signal handlers to accept the signal number, which they ignore
*H
*H  Revision 3.4  1993/12/17  07:17:51  mschoene
*H  included Harald's changes for OS/2
*H
*H  Revision 3.3  1993/10/29  12:01:33  martin
*H  fixed 'SyFgets' to copy terminating '\0'
*H
*H  Revision 3.2  1993/10/27  10:16:29  martin
*H  do not buffer 'stderr' under MS-DOS and TOS, use '\\' under MS-DOS and TOS
*H
*H  Revision 3.1  1993/10/18  12:45:07  martin
*H  initial revision under RCS (of the new system file)
*H
*/

#include        "system.h"              /* declaration part of the package */

#ifdef SYS_HAS_ANSI
# define SYS_ANSI       SYS_HAS_ANSI
#else
# ifdef __STDC__
#  define SYS_ANSI      1
# else
#  define SYS_ANSI      0
# endif
#endif

#ifdef SYS_HAS_CONST
# define SYS_CONST      SYS_HAS_CONST
#else
# ifdef __STDC__
#  define SYS_CONST     const
# else
#  define SYS_CONST
# endif
#endif


/****************************************************************************
**
*V  SyFlags . . . . . . . . . . . . . . . . . . . . flags used when compiling
**
**  'SyFlags' is the name of the target for which GAP was compiled.
**
**  It is '[bsd|mach|usg|os2|msdos|tos|vms|mac] [gcc|emx|djgpp|mpw|syc] [ansi]'.
**
**  It is used in 'InitGap' for the 'VERSYS' variable.
*/
char            SyFlags [] = {

#ifdef SYS_IS_BSD
    'b', 's', 'd',
# define SYS_BSD        1
#else
# define SYS_BSD        0
#endif

#ifdef SYS_IS_MACH
    'm', 'a', 'c', 'h',
# define SYS_MACH       1
#else
# define SYS_MACH       0
#endif

#ifdef SYS_IS_USG
    'u', 's', 'g',
# define SYS_USG        1
#else
# define SYS_USG        0
#endif

#ifdef SYS_IS_OS2_EMX
    'o', 's', '2', ' ', 'e', 'm', 'x',
# define SYS_OS2_EMX    1
#else
# define SYS_OS2_EMX    0
#endif

#ifdef SYS_IS_MSDOS_DJGPP
    'm', 's', 'd', 'o', 's', ' ', 'd', 'j', 'g', 'p', 'p',
# define SYS_MSDOS_DJGPP 1
#else
# define SYS_MSDOS_DJGPP 0
#endif

#ifdef SYS_IS_TOS_GCC2
    't', 'o', 's', ' ', 'g', 'c', 'c', '2',
# define SYS_TOS_GCC2   1
#else
# define SYS_TOS_GCC2   0
#endif

#ifdef SYS_IS_VMS
    'v', 'm', 's',
# define SYS_VMS        1
#else
# define SYS_VMS        0
#endif

#ifdef __MWERKS__
# define SYS_IS_MAC_MPW
# define SYS_HAS_CALLOC_PROTO
#endif

#ifdef SYS_IS_MAC_MPW
    'm', 'a', 'c', ' ', 'm', 'p', 'w',
# define SYS_MAC_MPW    1
#else
# define SYS_MAC_MPW    0
#endif

#ifdef SYS_IS_MAC_SYC
    'm', 'a', 'c', ' ', 's', 'y', 'c',
# define SYS_MAC_SYC    1
#else
# define SYS_MAC_SYC    0
#endif

#if __GNUC__
    ' ', 'g', 'c', 'c',
#endif
#if SYS_ANSI
    ' ', 'a', 'n', 's', 'i',
#endif

#ifdef SYS_HAS_BROKEN_STRNCAT
    ' ', 's', 't', 'r', 'n', 'c', 'a', 't',
#endif

    '\0' };


/****************************************************************************
**
*V  SyStackSpace  . . . . . . . . . . . . . . . . . . . amount of stack space
**
**  'SyStackSpace' is the amount of stackspace that GAP gets.
**
**  Under TOS and on the  Mac special actions must  be  taken to ensure  that
**  enough space is available.
*/
#if SYS_TOS_GCC2
# define __NO_INLINE__
int             _stksize = 64 * 1024;   /* GNU C, amount of stack space    */
long            SyStackSpace = 64 * 1024;
#endif

#if SYS_MAC_MPW || SYS_MAC_SYC
long            SyStackSpace = 64 * 1024;
#endif


/****************************************************************************
**
*V  SyLibname . . . . . . . . . . . . . . . . . name of the library directory
**
**  'SyLibname' is the name of the directory where the GAP library files  are
**  located.
**
**  This is per default the subdirectory 'lib/'  of  the  current  directory.
**  It is usually changed with the '-l' option in the script that starts GAP.
**
**  Is copied into the GAP variable called 'LIBNAME'  and used by  'Readlib'.
**  This is also used in 'LIBNAME/init.g' to find the group library directory
**  by replacing 'lib' with 'grp', etc.
**
**  It must end with the pathname seperator, eg. if 'init.g' is the name of a
**  library file 'strcat( SyLibname, "init.g" );' must be a  valid  filename.
**  Further neccessary transformation of the filename are done  in  'SyOpen'.
**
**  Put in this package because the command line processing takes place here.
*/
#if SYS_BSD || SYS_MACH || SYS_USG || SYS_OS2_EMX
char            SyLibname [256] = "lib/";
#endif
#if SYS_MSDOS_DJGPP || SYS_TOS_GCC2
char            SyLibname [256] = "lib\\";
#endif
#if SYS_VMS
char            SyLibname [256] = "[.lib]";
#endif
#if SYS_MAC_MPW || SYS_MAC_SYC
char            SyLibname [256] = ":lib:";
#endif


/****************************************************************************
**
*V  SyHelpname  . . . . . . . . . . . . . . name of the online help directory
**
**  'SyHelpname' is the name of the directory where the GAP online help files
**  are located.
**
**  By default it is computed from 'SyLibname' by replacing 'lib' with 'doc'.
**  It can be changed with the '-h' option.
**
**  It is used by 'SyHelp' to find the online documentation.
*/
char            SyHelpname [256];


/****************************************************************************
**
*V  SyBanner  . . . . . . . . . . . . . . . . . . . . . . . . surpress banner
**
**  'SyBanner' determines whether GAP should print the banner.
**
**  Per default it  is true,  i.e.,  GAP prints the  nice  banner.  It can be
**  changed by the '-b' option to have GAP surpress the banner.
**
**  It is copied into the GAP variable 'BANNER', which  is used  in 'init.g'.
**
**  Put in this package because the command line processing takes place here.
*/
long            SyBanner = 1;


/****************************************************************************
**
*V  SyQuiet . . . . . . . . . . . . . . . . . . . . . . . . . surpress prompt
**
**  'SyQuit' determines whether GAP should print the prompt and  the  banner.
**
**  Per default its false, i.e. GAP prints the prompt and  the  nice  banner.
**  It can be changed by the '-q' option to have GAP operate in silent  mode.
**
**  It is used by the functions in 'gap.c' to surpress printing the  prompts.
**  Is also copied into the GAP variable 'QUIET' which is used  in  'init.g'.
**
**  Put in this package because the command line processing takes place here.
*/
long            SyQuiet = 0;


/****************************************************************************
**
*V  SyNrCols  . . . . . . . . . . . . . . . . . .  length of the output lines
**
**  'SyNrCols' is the length of the lines on the standard output  device.
**
**  Per default this is 80 characters which is the usual width of  terminals.
**  It can be changed by the '-x' options for larger terminals  or  printers.
**
**  'Pr' uses this to decide where to insert a <newline> on the output lines.
**  'SyRead' uses it to decide when to start scrolling the echoed input line.
**
**  Put in this package because the command line processing takes place here.
*/
long            SyNrCols = 80;


/****************************************************************************
**
*V  SyNrRows  . . . . . . . . . . . . . . . . . number of lines on the screen
**
**  'SyNrRows' is the number of lines on the standard output device.
**
**  Per default this is 24, which is the  usual  size  of  terminal  screens.
**  It can be changed with the '-y' option for larger terminals or  printers.
**
**  'SyHelp' uses this to decide where to stop with '-- <space> for more --'.
*/
long            SyNrRows = 24;


/****************************************************************************
**
*V  SyGasman  . . . . . . . . . . . . . . . . . . . .  enable gasman messages
**
**  'SyGasman' determines whether garabage collections are reported  or  not.
**
**  Per default it is false, i.e. Gasman is silent about garbage collections.
**  It can be changed by using the  '-g'  option  on the  GAP  command  line.
**
**  This is used in  'CollectGarbage'  to decide whether to be silent or not.
**
**  Put in this package because the command line processing takes place here.
*/
long            SyGasman = 0;


/****************************************************************************
**
*V  SyMemory  . . . . . . . . . . . . . .  default size for initial workspace
**
**  'SyMemory' is the size of the  initial  workspace  allocated  by  Gasman.
**
**  This is per default  4 Megabyte,  which  is  often  a  reasonable  value.
**  It is usually changed with the '-m' option in the script that starts GAP.
**
**  This value is used in 'InitGasman' to allocate the initial workspace.
**
**  Put in this package because the command line processing takes place here.
*/
#if SYS_BSD || SYS_MACH || SYS_USG || SYS_OS2_EMX
long            SyMemory = 4 * 1024 * 1024;
#endif
#if SYS_MSDOS_DJGPP
long            SyMemory = 4 * 1024 * 1024;
#endif
#if SYS_TOS_GCC2
long            SyMemory = 0;
#endif
#if SYS_VMS
long            SyMemory = 4 * 1024 * 1024;
#endif
#if SYS_MAC_MPW || SYS_MAC_SYC
long            SyMemory = 0;
#endif


/****************************************************************************
**
*V  SyInitfiles[] . . . . . . . . . . .  list of filenames to be read in init
**
**  'SyInitfiles' is a list of file to read upon startup of GAP.
**
**  It contains the 'init.g' file and a user specific init file if it exists.
**  It also contains all names all the files specified on the  command  line.
**
**  This is used in 'InitGap' which tries to read those files  upon  startup.
**
**  Put in this package because the command line processing takes place here.
**
**  For UNIX this list contains 'LIBNAME/init.g' and '$HOME/.gaprc'.
*/
char            SyInitfiles [16] [256];


/****************************************************************************
**
*V  syWindow  . . . . . . . . . . . . . . . .  running under a window handler
**
**  'syWindow' is 1 if GAP  is running under  a window handler front end such
**  as 'xgap', and 0 otherwise.
**
**  If running under  a window handler front  end, GAP adds various  commands
**  starting with '@' to the output to let 'xgap' know what is going on.
*/
long            syWindow = 0;


/****************************************************************************
**
*V  syStartTime . . . . . . . . . . . . . . . . . . time when GAP was started
*V  syStopTime  . . . . . . . . . . . . . . . . . . time when reading started
*/
unsigned long   syStartTime;
unsigned long   syStopTime;


/****************************************************************************
**
*F  IsAlpha( <ch> ) . . . . . . . . . . . . .  is a character a normal letter
*F  IsDigit( <ch> ) . . . . . . . . . . . . . . . . .  is a character a digit
**
**  'IsAlpha' returns 1 if its character argument is a normal character  from
**  the range 'a..zA..Z' and 0 otherwise.
**
**  'IsDigit' returns 1 if its character argument is a digit from  the  range
**  '0..9' and 0 otherwise.
**
**  'IsAlpha' and 'IsDigit' are implemented in the declaration part  of  this
**  package as follows:
**
#include        <ctype.h>
#define IsAlpha(ch)     (isalpha(ch))
#define IsDigit(ch)     (isdigit(ch))
*/


/****************************************************************************
**
*F  SyStrlen( <str> ) . . . . . . . . . . . . . . . . . .  length of a string
**
**  'SyStrlen' returns the length of the string <str>, i.e.,  the  number  of
**  characters in <str> that precede the terminating null character.
*/
#ifndef SYS_STRING_H                    /* string functions                */
# include      <string.h>
# define SYS_STRING_H
#endif
#ifndef SYS_HAS_STRING_PROTO            /* ANSI/TRAD decl. from H&S 13     */
# if SYS_ANSI
extern  char *          strncat P(( char *, SYS_CONST char *, size_t ));
extern  int             strcmp P(( SYS_CONST char *, SYS_CONST char * ));
extern  size_t          strlen P(( SYS_CONST char * ));
# else
extern  char *          strncat P(( char *, SYS_CONST char *, int ));
extern  int             strcmp P(( SYS_CONST char *, SYS_CONST char * ));
extern  int             strlen P(( SYS_CONST char * ));
# endif
#endif

long            SyStrlen ( str )
    char *              str;
{
    return strlen( str );
}


/****************************************************************************
**
*F  SyStrcmp( <str1>, <str2> )  . . . . . . . . . . . . . compare two strings
**
**  'SyStrcmp' returns an integer greater than, equal to, or less  than  zero
**  according to whether <str1> is greater  than,  equal  to,  or  less  than
**  <str2> lexicographically.
*/
long            SyStrcmp ( str1, str2 )
    char *              str1;
    char *              str2;
{
    return strcmp( str1, str2 );
}


/****************************************************************************
**
*F  SyStrncat( <dst>, <src>, <len> )  . . . . .  append one string to another
**
**  'SyStrncat'  appends characters from the  <src>  to <dst>  until either a
**  null character  is  encoutered  or  <len>  characters have   been copied.
**  <dst> becomes the concatenation of <dst> and <src>.  The resulting string
**  is always null terminated.  'SyStrncat' returns a pointer to <dst>.
*/
#ifdef SYS_HAS_BROKEN_STRNCAT
char *          SyStrncat ( dst, src, len )
    char *              dst;
    char *              src;
    long                len;
{
    char *              p;
    char *              q;

    for ( p = dst;  *p;  p++ )
        ;
    for ( q = src;  *q && 0 < len;  len-- )
        *p++ = *q++;
    *p = 0;
    return dst;
}
#else
char *          SyStrncat ( dst, src, len )
    char *              dst;
    char *              src;
    long                len;
{
    return strncat( dst, src, len );
}
#endif


/****************************************************************************
**
*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 theis  buffers  using  'malloc',  which would
**  otherwise confuse Gasman.
*/
#ifndef SYS_STDIO_H                     /* standard input/output functions */
# include       <stdio.h>
# define SYS_STDIO_H
#endif
#ifndef SYS_HAS_STDIO_PROTO             /* ANSI/TRAD decl. from H&S 15     */
extern  FILE *          fopen P(( SYS_CONST char *, SYS_CONST char * ));
extern  int             fclose P(( FILE * ));
extern  void            setbuf P(( FILE *, char * ));
extern  char *          fgets P(( char *, int, FILE * ));
extern  int             fputs P(( SYS_CONST char *, FILE * ));
#endif

struct {
    FILE *      fp;                     /* file pointer for this file      */
    FILE *      echo;                   /* file pointer for the echo       */
    char        buf [BUFSIZ];           /* the buffer for this file        */
}       syBuf [16];


/****************************************************************************
**
*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.
*/
long            SyFopen ( name, mode )
    char *              name;
    char *              mode;
{
    long                fid;

    /* handle standard files                                               */
    if ( SyStrcmp( name, "*stdin*" ) == 0 ) {
        if ( SyStrcmp( mode, "r" ) != 0 )  return -1;
        return 0;
    }
    else if ( SyStrcmp( name, "*stdout*" ) == 0 ) {
        if ( SyStrcmp( mode, "w" ) != 0 )  return -1;
        return 1;
    }
    else if ( SyStrcmp( name, "*errin*" ) == 0 ) {
        if ( SyStrcmp( mode, "r" ) != 0 )  return -1;
        if ( syBuf[2].fp == (FILE*)0 )  return -1;
        return 2;
    }
    else if ( SyStrcmp( name, "*errout*" ) == 0 ) {
        if ( SyStrcmp( mode, "w" ) != 0 )  return -1;
        return 3;
    }

    /* try to find an unused file identifier                               */
    for ( fid = 4; fid < sizeof(syBuf)/sizeof(syBuf[0]); ++fid )
        if ( syBuf[fid].fp == (FILE*)0 )  break;
    if ( fid == sizeof(syBuf)/sizeof(syBuf[0]) )
        return (long)-1;

    /* try to open the file                                                */
    syBuf[fid].fp = fopen( name, mode );
    if ( syBuf[fid].fp == (FILE*)0 )
        return (long)-1;

    /* allocate the buffer                                                 */
    setbuf( syBuf[fid].fp, syBuf[fid].buf );

    /* return file identifier                                              */
    return fid;
}


/****************************************************************************
**
*F  SyFclose( <fid> ) . . . . . . . . . . . . . . . . .  close the file <fid>
**
**  'SyFclose' closes the file with the identifier <fid>  which  is  obtained
**  from 'SyFopen'.
*/
void            SyFclose ( fid )
    long                fid;
{
    /* check file identifier                                               */
    if ( syBuf[fid].fp == (FILE*)0 ) {
        fputs("gap: panic 'SyFclose' asked to close closed file!\n",stderr);
        SyExit( 1 );
    }

    /* refuse to close the standard files                                  */
    if ( fid == 0 || fid == 1 || fid == 2 || fid == 3 ) {
        return;
    }

    /* try to close the file                                               */
    if ( fclose( syBuf[fid].fp ) == EOF ) {
        fputs("gap: 'SyFclose' cannot close file, ",stderr);
        fputs("maybe your file system is full?\n",stderr);
    }

    /* mark the buffer as unused                                           */
    syBuf[fid].fp = (FILE*)0;
}


/****************************************************************************
**
*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.
*/
extern  int             syStartraw P(( long fid ));
extern  void            syStopraw  P(( long fid ));
extern  int             syGetch    P(( long fid ));
#if SYS_MAC_SYC
extern  int             syGetch2   P(( long fid, int cur ));
#endif
extern  void            syEchoch   P(( int ch, long fid ));
extern  void            syEchos    P(( char * str, long fid ));

extern  unsigned long   iscomplete P(( char *           name,
                                       unsigned long    len,
                                       unsigned long    rn ));
extern  unsigned long   completion P(( char *           name,
                                       unsigned long    len,
                                       unsigned long    rn ));

extern  void            syWinPut   P(( long fid, char * cmd, char * str ));

long            syLineEdit = 1;         /* 0: no line editing              */
                                        /* 1: line editing if terminal     */
                                        /* 2: always line editing (EMACS)  */
long            syCTRD = 1;             /* true if '<ctr>-D' is <eof>      */
long            syNrchar;               /* nr of chars already on the line */
char            syPrompt [256];         /* characters alread on the line   */

char            syHistory [8192];       /* history of command lines        */
char *          syHi = syHistory;       /* actual position in history      */
int             syCTRO;                 /* number of '<ctr>-O' pending     */

#define CTR(C)          ((C) & 0x1F)    /* <ctr> character                 */
#define ESC(C)          ((C) | 0x100)   /* <esc> character                 */
#define CTV(C)          ((C) | 0x200)   /* <ctr>V quotes characters        */

#define IS_SEP(C)       (!IsAlpha(C) && !IsDigit(C) && (C)!='_')

char *          SyFgets ( line, length, fid )
    char                line [];
    long                length;
    long                fid;
{
    int                 ch,  ch2,  ch3, last;
    char                * p,  * q,  * r,  * s,  * t;
    char                * h;
    static char         yank [512];
    char                old [512],  new [512];
    int                 oldc,  newc;
    int                 rep;
    char                buffer [512];
    int                 rn;

    /* no line editing if the file is not '*stdin*' or '*errin*'           */
    if ( fid != 0 && fid != 2 ) {
        p = fgets( line, (int)length, syBuf[fid].fp );
        return p;
    }

    /* no line editing if the user disabled it                             */
    if ( syLineEdit == 0 ) {
        syStopTime = SyTime();
        p = fgets( line, (int)length, syBuf[fid].fp );
        syStartTime += SyTime() - syStopTime;
        return p;
    }

    /* no line editing if the file cannot be turned to raw mode            */
    if ( syLineEdit == 1 && ! syStartraw(fid) ) {
        syStopTime = SyTime();
        p = fgets( line, (int)length, syBuf[fid].fp );
        syStartTime += SyTime() - syStopTime;
        return p;
    }

    /* stop the clock, reading should take no time                         */
    syStopTime = SyTime();

    /* the line starts out blank                                           */
    line[0] = '\0';  p = line;  h = syHistory;
    for ( q = old; q < old+sizeof(old); ++q )  *q = ' ';
    oldc = 0;
    last = 0;

    while ( 1 ) {

        /* get a character, handle <ctr>V<chr>, <esc><num> and <ctr>U<num> */
        rep = 1;  ch2 = 0;
        do {
            if ( syCTRO % 2 == 1  )  { ch = CTR('N'); syCTRO = syCTRO - 1; }
            else if ( syCTRO != 0 )  { ch = CTR('O'); rep = syCTRO / 2; }
#if ! SYS_MAC_SYC
            else ch = syGetch(fid);
#endif
#if SYS_MAC_SYC
            else ch = syGetch2(fid,*p);
#endif
            if ( ch2==0        && ch==CTR('V') ) {             ch2=ch; ch=0;}
            if ( ch2==0        && ch==CTR('[') ) {             ch2=ch; ch=0;}
            if ( ch2==0        && ch==CTR('U') ) {             ch2=ch; ch=0;}
            if ( ch2==CTR('[') && ch==CTR('V') ) { ch2=ESC(CTR('V'));  ch=0;}
            if ( ch2==CTR('[') && isdigit(ch)  ) { rep=ch-'0'; ch2=ch; ch=0;}
            if ( ch2==CTR('[') && ch=='['      ) {             ch2=ch; ch=0;}
            if ( ch2==CTR('U') && ch==CTR('V') ) { rep=4*rep;  ch2=ch; ch=0;}
            if ( ch2==CTR('U') && ch==CTR('[') ) { rep=4*rep;  ch2=ch; ch=0;}
            if ( ch2==CTR('U') && ch==CTR('U') ) { rep=4*rep;  ch2=ch; ch=0;}
            if ( ch2==CTR('U') && isdigit(ch)  ) { rep=ch-'0'; ch2=ch; ch=0;}
            if ( isdigit(ch2)  && ch==CTR('V') ) {             ch2=ch; ch=0;}
            if ( isdigit(ch2)  && ch==CTR('[') ) {             ch2=ch; ch=0;}
            if ( isdigit(ch2)  && ch==CTR('U') ) {             ch2=ch; ch=0;}
            if ( isdigit(ch2)  && isdigit(ch)  ) { rep=10*rep+ch-'0';  ch=0;}
        } while ( ch == 0 );
        if ( ch2==CTR('V') )       ch  = CTV(ch);
        if ( ch2==ESC(CTR('V')) )  ch  = CTV(ch | 0x80);
        if ( ch2==CTR('[') )       ch  = ESC(ch);
        if ( ch2==CTR('U') )       rep = 4*rep;
        if ( ch2=='[' && ch=='A')  ch  = CTR('P');
        if ( ch2=='[' && ch=='B')  ch  = CTR('N');
        if ( ch2=='[' && ch=='C')  ch  = CTR('F');
        if ( ch2=='[' && ch=='D')  ch  = CTR('B');

        /* now perform the requested action <rep> times in the input line  */
        while ( rep-- > 0 ) {
            switch ( ch ) {

            case CTR('A'): /* move cursor to the start of the line         */
                while ( p > line )  --p;
                break;

            case ESC('B'): /* move cursor one word to the left             */
            case ESC('b'):
                if ( p > line ) do {
                    --p;
                } while ( p>line && (!IS_SEP(*(p-1)) || IS_SEP(*p)));
                break;

            case CTR('B'): /* move cursor one character to the left        */
                if ( p > line )  --p;
                break;

            case CTR('F'): /* move cursor one character to the right       */
                if ( *p != '\0' )  ++p;
                break;

            case ESC('F'): /* move cursor one word to the right            */
            case ESC('f'):
                if ( *p != '\0' ) do {
                    ++p;
                } while ( *p!='\0' && (IS_SEP(*(p-1)) || !IS_SEP(*p)));
                break;

            case CTR('E'): /* move cursor to the end of the line           */
                while ( *p != '\0' )  ++p;
                break;

            case CTR('H'): /* delete the character left of the cursor      */
            case 127:
                if ( p == line ) break;
                --p;
                /* let '<ctr>-D' do the work                               */

            case CTR('D'): /* delete the character at the cursor           */
                           /* on an empty line '<ctr>-D' is <eof>          */
                if ( p == line && *p == '\0' && syCTRD ) {
                    ch = EOF; rep = 0; break;
                }
                if ( *p != '\0' ) {
                    for ( q = p; *(q+1) != '\0'; ++q )
                        *q = *(q+1);
                    *q = '\0';
                }
                break;

            case CTR('X'): /* delete the line                              */
                p = line;
                /* let '<ctr>-K' do the work                               */

            case CTR('K'): /* delete to end of line                        */
                if ( last!=CTR('X') && last!=CTR('K') && last!=ESC(127)
                  && last!=ESC('D') && last!=ESC('d') )  yank[0] = '\0';
                for ( r = yank; *r != '\0'; ++r ) ;
                for ( s = p; *s != '\0'; ++s )  r[s-p] = *s;
                r[s-p] = '\0';
                *p = '\0';
                break;

            case ESC(127): /* delete the word left of the cursor           */
                q = p;
                if ( p > line ) do {
                    --p;
                } while ( p>line && (!IS_SEP(*(p-1)) || IS_SEP(*p)));
                if ( last!=CTR('X') && last!=CTR('K') && last!=ESC(127)
                  && last!=ESC('D') && last!=ESC('d') )  yank[0] = '\0';
                for ( r = yank; *r != '\0'; ++r ) ;
                for ( ; yank <= r; --r )  r[q-p] = *r;
                for ( s = p; s < q; ++s )  yank[s-p] = *s;
                for ( r = p; *q != '\0'; ++q, ++r )
                    *r = *q;
                *r = '\0';
                break;

            case ESC('D'): /* delete the word right of the cursor          */
            case ESC('d'):
                q = p;
                if ( *q != '\0' ) do {
                    ++q;
                } while ( *q!='\0' && (IS_SEP(*(q-1)) || !IS_SEP(*q)));
                if ( last!=CTR('X') && last!=CTR('K') && last!=ESC(127)
                  && last!=ESC('D') && last!=ESC('d') )  yank[0] = '\0';
                for ( r = yank; *r != '\0'; ++r ) ;
                for ( s = p; s < q; ++s )  r[s-p] = *s;
                r[s-p] = '\0';
                for ( r = p; *q != '\0'; ++q, ++r )
                    *r = *q;
                *r = '\0';
                break;

            case CTR('T'): /* twiddle characters                           */
                if ( p == line )  break;
                if ( *p == '\0' )  --p;
                if ( p == line )  break;
                ch2 = *(p-1);  *(p-1) = *p;  *p = ch2;
                ++p;
                break;

            case CTR('L'): /* insert last input line                       */
                for ( r = syHistory; *r != '\0' && *r != '\n'; ++r ) {
                    ch2 = *r;
                    for ( q = p; ch2; ++q ) {
                        ch3 = *q; *q = ch2; ch2 = ch3;
                    }
                    *q = '\0'; ++p;
                }
                break;

            case CTR('Y'): /* insert (yank) deleted text                   */
                for ( r = yank; *r != '\0' && *r != '\n'; ++r ) {
                    ch2 = *r;
                    for ( q = p; ch2; ++q ) {
                        ch3 = *q; *q = ch2; ch2 = ch3;
                    }
                    *q = '\0'; ++p;
                }
                break;

            case CTR('P'): /* fetch old input line                         */
                while ( *h != '\0' ) {
                    for ( q = line; q < p; ++q )
                        if ( *q != h[q-line] )  break;
                    if ( q == p )  break;
                    while ( *h != '\n' && *h != '\0' )  ++h;
                    if ( *h == '\n' ) ++h;
                }
                q = p;
                while ( *h!='\0' && h[q-line]!='\n' && h[q-line]!='\0' ) {
                    *q = h[q-line];  ++q;
                }
                *q = '\0';
                while ( *h != '\0' && *h != '\n' )  ++h;
                if ( *h == '\n' ) ++h;  else h = syHistory;
                syHi = h;
                break;

            case CTR('N'): /* fetch next input line                        */
                h = syHi;
                if ( h > syHistory ) {
                    do {--h;} while (h>syHistory && *(h-1)!='\n');
                    if ( h==syHistory )  while ( *h != '\0' ) ++h;
                }
                while ( *h != '\0' ) {
                    if ( h==syHistory )  while ( *h != '\0' ) ++h;
                    do {--h;} while (h>syHistory && *(h-1)!='\n');
                    for ( q = line; q < p; ++q )
                        if ( *q != h[q-line] )  break;
                    if ( q == p )  break;
                    if ( h==syHistory )  while ( *h != '\0' ) ++h;
                }
                q = p;
                while ( *h!='\0' && h[q-line]!='\n' && h[q-line]!='\0' ) {
                    *q = h[q-line];  ++q;
                }
                *q = '\0';
                while ( *h != '\0' && *h != '\n' )  ++h;
                if ( *h == '\n' ) ++h;  else h = syHistory;
                syHi = h;
                break;

            case ESC('<'): /* goto beginning of the history                */
                while ( *h != '\0' ) ++h;
                do {--h;} while (h>syHistory && *(h-1)!='\n');
                q = p = line;
                while ( *h!='\0' && h[q-line]!='\n' && h[q-line]!='\0' ) {
                    *q = h[q-line];  ++q;
                }
                *q = '\0';
                while ( *h != '\0' && *h != '\n' )  ++h;
                if ( *h == '\n' ) ++h;  else h = syHistory;
                syHi = h;
                break;

            case ESC('>'): /* goto end of the history                      */
                h = syHistory;
                p = line;
                *p = '\0';
                syHi = h;
                break;

            case CTR('S'): /* search for a line forward                    */
                /* search for a line forward, not fully implemented !!!    */
                if ( *p != '\0' ) {
                    ch2 = syGetch(fid);
                    q = p+1;
                    while ( *q != '\0' && *q != ch2 )  ++q;
                    if ( *q == ch2 )  p = q;
                }
                break;

            case CTR('R'): /* search for a line backward                   */
                /* search for a line backward, not fully implemented !!!   */
                if ( p > line ) {
                    ch2 = syGetch(fid);
                    q = p-1;
                    while ( q > line && *q != ch2 )  --q;
                    if ( *q == ch2 )  p = q;
                }
                break;

            case ESC('U'): /* uppercase word                               */
            case ESC('u'):
                if ( *p != '\0' ) do {
                    if ('a' <= *p && *p <= 'z')  *p = *p + 'A' - 'a';
                    ++p;
                } while ( *p!='\0' && (IS_SEP(*(p-1)) || !IS_SEP(*p)));
                break;

            case ESC('C'): /* capitalize word                              */
            case ESC('c'):
                while ( *p!='\0' && IS_SEP(*p) )  ++p;
                if ( 'a' <= *p && *p <= 'z' )  *p = *p + 'A'-'a';
                if ( *p != '\0' ) ++p;
                /* lowercase rest of the word                              */

            case ESC('L'): /* lowercase word                               */
            case ESC('l'):
                if ( *p != '\0' ) do {
                    if ('A' <= *p && *p <= 'Z')  *p = *p + 'a' - 'A';
                    ++p;
                } while ( *p!='\0' && (IS_SEP(*(p-1)) || !IS_SEP(*p)));
                break;

            case ESC(CTR('L')): /* repaint input line                      */
                syEchoch('\n',fid);
                for ( q = syPrompt; q < syPrompt+syNrchar; ++q )
                    syEchoch( *q, fid );
                for ( q = old; q < old+sizeof(old); ++q )  *q = ' ';
                oldc = 0;
                break;

            case EOF:     /* end of file on input                          */
                break;

            case CTR('M'): /* append \n and exit                           */
            case CTR('J'):
                while ( *p != '\0' )  ++p;
                *p++ = '\n'; *p = '\0';
                rep = 0;
                break;

            case CTR('O'): /* accept line, perform '<ctr>-N' next time     */
                while ( *p != '\0' )  ++p;
                *p++ = '\n'; *p = '\0';
                syCTRO = 2 * rep + 1;
                rep = 0;
                break;

            case CTR('I'): /* try to complete the identifier before dot    */
                if ( p == line || IS_SEP(p[-1]) ) {
                    ch2 = ch & 0xff;
                    for ( q = p; ch2; ++q ) {
                        ch3 = *q; *q = ch2; ch2 = ch3;
                    }
                    *q = '\0'; ++p;
                }
                else {
                    if ( (q = p) > line ) do {
                        --q;
                    } while ( q>line && (!IS_SEP(*(q-1)) || IS_SEP(*q)));
                    rn = (line < q && *(q-1) == '.');
                    r = buffer;  s = q;
                    while ( s < p )  *r++ = *s++;
                    *r = '\0';
                    if ( iscomplete( buffer, p-q, rn ) ) {
                        if ( last != CTR('I') )
                            syEchoch( CTR('G'), fid );
                        else {
                            syWinPut( fid, "@c", "" );
                            syEchos( "\n    ", fid );
                            syEchos( buffer, fid );
                            while ( completion( buffer, p-q, rn ) ) {
                                syEchos( "\n    ", fid );
                                syEchos( buffer, fid );
                            }
                            syEchos( "\n", fid );
                            for ( q=syPrompt; q<syPrompt+syNrchar; ++q )
                                syEchoch( *q, fid );
                            for ( q = old; q < old+sizeof(old); ++q )
                                *q = ' ';
                            oldc = 0;
                            syWinPut( fid, (fid == 0 ? "@i" : "@e"), "" );
                        }
                    }
                    else if ( ! completion( buffer, p-q, rn ) ) {
                        if ( last != CTR('I') )
                            syEchoch( CTR('G'), fid );
                        else {
                            syWinPut( fid, "@c", "" );
                            syEchos("\n    identifier has no completions\n",
                                    fid);
                            for ( q=syPrompt; q<syPrompt+syNrchar; ++q )
                                syEchoch( *q, fid );
                            for ( q = old; q < old+sizeof(old); ++q )
                                *q = ' ';
                            oldc = 0;
                            syWinPut( fid, (fid == 0 ? "@i" : "@e"), "" );
                        }
                    }
                    else {
                        t = p;
                        for ( s = buffer+(p-q); *s != '\0'; s++ ) {
                            ch2 = *s;
                            for ( r = p; ch2; r++ ) {
                                ch3 = *r; *r = ch2; ch2 = ch3;
                            }
                            *r = '\0'; p++;
                        }
                        while ( t < p && completion( buffer, t-q, rn ) ) {
                            r = t;  s = buffer+(t-q);
                            while ( r < p && *r == *s ) {
                                r++; s++;
                            }
                            s = p;  p = r;
                            while ( *s != '\0' )  *r++ = *s++;
                            *r = '\0';
                        }
                        if ( t == p ) {
                            if ( last != CTR('I') )
                                syEchoch( CTR('G'), fid );
                            else {
                                syWinPut( fid, "@c", "" );
                                buffer[t-q] = '\0';
                                while ( completion( buffer, t-q, rn ) ) {
                                    syEchos( "\n    ", fid );
                                    syEchos( buffer, fid );
                                }
                                syEchos( "\n", fid );
                                for ( q=syPrompt; q<syPrompt+syNrchar; ++q )
                                    syEchoch( *q, fid );
                                for ( q = old; q < old+sizeof(old); ++q )
                                    *q = ' ';
                                oldc = 0;
                                syWinPut( fid, (fid == 0 ? "@i" : "@e"), "");
                            }
                        }
                    }
                }
                break;

            default:      /* default, insert normal character              */
                ch2 = ch & 0xff;
                for ( q = p; ch2; ++q ) {
                    ch3 = *q; *q = ch2; ch2 = ch3;
                }
                *q = '\0'; ++p;
                break;

            } /* switch ( ch ) */

            last = ch;

        }

        if ( ch==EOF || ch=='\n' || ch=='\r' || ch==CTR('O') ) {
            syEchoch('\r',fid);  syEchoch('\n',fid);  break;
        }

        /* now update the screen line according to the differences         */
        for ( q = line, r = new, newc = 0; *q != '\0'; ++q ) {
            if ( q == p )  newc = r-new;
            if ( *q==CTR('I') )  { do *r++=' '; while ((r-new+syNrchar)%8); }
            else if ( *q==0x7F ) { *r++ = '^'; *r++ = '?'; }
            else if ( '\0'<=*q && *q<' '  ) { *r++ = '^'; *r++ = *q+'@'; }
            else if ( ' ' <=*q && *q<0x7F ) { *r++ = *q; }
            else {
                *r++ = '\\';                   *r++ = '0'+(unsigned)*q/64%4;
                *r++ = '0'+(unsigned)*q/8 %8;  *r++ = '0'+(unsigned)*q   %8;
            }
            if ( r >= new+SyNrCols-syNrchar-2 ) {
                if ( q >= p ) { q++; break; }
                new[0] = '$';   new[1] = r[-5]; new[2] = r[-4];
                new[3] = r[-3]; new[4] = r[-2]; new[5] = r[-1];
                r = new+6;
            }
        }
        if ( q == p )  newc = r-new;
        for (      ; r < new+sizeof(new); ++r )  *r = ' ';
        if ( q[0] != '\0' && q[1] != '\0' )
            new[SyNrCols-syNrchar-2] = '$';
        else if ( q[1] == '\0' && ' ' <= *q && *q < 0x7F )
            new[SyNrCols-syNrchar-2] = *q;
        else if ( q[1] == '\0' && q[0] != '\0' )
            new[SyNrCols-syNrchar-2] = '$';
        for ( q = old, r = new; r < new+sizeof(new); ++r, ++q ) {
            if ( *q == *r )  continue;
            while (oldc<(q-old)) { syEchoch(old[oldc],fid);  ++oldc; }
            while (oldc>(q-old)) { syEchoch('\b',fid);       --oldc; }
            *q = *r;  syEchoch( *q, fid ); ++oldc;
        }
        while ( oldc < newc ) { syEchoch(old[oldc],fid);  ++oldc; }
        while ( oldc > newc ) { syEchoch('\b',fid);       --oldc; }

    }

    /* Now we put the new string into the history,  first all old strings  */
    /* are moved backwards,  then we enter the new string in syHistory[].  */
    for ( q = syHistory+sizeof(syHistory)-3; q >= syHistory+(p-line); --q )
        *q = *(q-(p-line));
    for ( p = line, q = syHistory; *p != '\0'; ++p, ++q )
        *q = *p;
    syHistory[sizeof(syHistory)-3] = '\n';
    if ( syHi != syHistory )
        syHi = syHi + (p-line);
    if ( syHi > syHistory+sizeof(syHistory)-2 )
        syHi = syHistory+sizeof(syHistory)-2;

    /* send the whole line (unclipped) to the window handler               */
    syWinPut( fid, (*line != '\0' ? "@r" : "@x"), line );

    /* strip away prompts (usefull for pasting old stuff)                  */
    if (line[0]=='g'&&line[1]=='a'&&line[2]=='p'&&line[3]=='>'&&line[4]==' ')
        for ( p = line, q = line+5; q[-1] != '\0'; p++, q++ )  *p = *q;
    if (line[0]=='b'&&line[1]=='r'&&line[2]=='k'&&line[3]=='>'&&line[4]==' ')
        for ( p = line, q = line+5; q[-1] != '\0'; p++, q++ )  *p = *q;
    if (line[0]=='>'&&line[1]==' ')
        for ( p = line, q = line+2; q[-1] != '\0'; p++, q++ )  *p = *q;

    /* switch back to cooked mode                                          */
    if ( syLineEdit == 1 )
        syStopraw(fid);

    /* start the clock again                                               */
    syStartTime += SyTime() - syStopTime;

    /* return the line (or '0' at end-of-file)                             */
    if ( *line == '\0' )
        return (char*)0;
    return line;
}


/****************************************************************************
**
*F  syStartraw(<fid>) . . . . . . . start raw mode on input file <fid>, local
*F  syStopraw(<fid>)  . . . . . . .  stop raw mode on input file <fid>, local
*F  syGetch(<fid>)  . . . . . . . . . . . . . .  get a char from <fid>, local
*F  syEchoch(<ch>,<fid>)  . . . . . . . . . . . . echo a char to <fid>, local
**
**  This four functions are the actual system dependent  part  of  'SyFgets'.
**
**  'syStartraw' tries to put the file with the file  identifier  <fid>  into
**  raw mode.  I.e.,  disabling  echo  and  any  buffering.  It also finds  a
**  place to put the echoing  for  'syEchoch'.  If  'syStartraw'  succedes it
**  returns 1, otherwise, e.g., if the <fid> is not a terminal, it returns 0.
**
**  'syStopraw' stops the raw mode for the file  <fid>  again,  switching  it
**  back into whatever mode the terminal had before 'syStartraw'.
**
**  'syGetch' reads one character from the file <fid>, which must  have  been
**  turned into raw mode before, and returns it.
**
**  'syEchoch' puts the character <ch> to the file opened by 'syStartraw' for
**  echoing.  Note that if the user redirected 'stdout' but not 'stdin',  the
**  echo for 'stdin' must go to 'ttyname(fileno(stdin))' instead of 'stdout'.
*/


/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
**
**  For Berkeley UNIX, input/output redirection and typeahead are  supported.
**  We switch the terminal line into 'CBREAK' mode and also disable the echo.
**  We do not switch to 'RAW'  mode because  this would flush  all typeahead.
**  Because 'CBREAK' leaves signals enabled we have to disable the characters
**  for interrupt and quit, which are usually set to '<ctr>-C' and '<ctr>-B'.
**  We also turn  off  the  xon/xoff  start and  stop characters,  which  are
**  usually set  to '<ctr>-S' and '<ctr>-Q' so  we can get  those characters.
**  We  do not  change the  suspend  character, which  is usually  '<ctr>-Z',
**  instead we catch the signal, so that we  can turn  the terminal line back
**  to cooked mode before stopping GAP and back to raw mode when continueing.
*/
#if SYS_BSD || SYS_MACH

#ifndef SYS_SGTTY_H                     /* terminal control functions      */
# include       <sgtty.h>
# define SYS_SGTTY_H
#endif
#ifndef SYS_HAS_IOCTL_PROTO             /* UNIX decl. from 'man'           */
extern  int             ioctl P(( int, unsigned long, char * ));
#endif

struct sgttyb   syOld, syNew;           /* old and new terminal state      */
struct tchars   syOldT, syNewT;         /* old and new special characters  */

#ifndef SYS_SIGNAL_H                    /* signal handling functions       */
# include       <signal.h>
# ifdef SYS_HAS_SIG_T
#  define SYS_SIG_T     SYS_HAS_SIG_T
# else
#  define SYS_SIG_T     void
# endif
# define SYS_SIGNAL_H
typedef SYS_SIG_T       sig_handler_t P(( int ));
#endif
#ifndef SYS_HAS_SIGNAL_PROTO            /* ANSI/TRAD decl. from H&S 19.6   */
extern  sig_handler_t * signal P(( int, sig_handler_t * ));
extern  int             getpid P(( void ));
extern  int             kill P(( int, int ));
#endif

#ifndef SYS_HAS_READ_PROTO              /* UNIX decl. from 'man'           */
extern  int             read P(( int, char *, int ));
extern  int             write P(( int, char *, int ));
#endif

#ifdef SIGTSTP

long            syFid;

SYS_SIG_T       syAnswerCont ( signr )
    int                 signr;
{
    syStartraw( syFid );
    signal( SIGCONT, SIG_DFL );
    kill( getpid(), SIGCONT );
#ifdef SYS_HAS_SIG_T
    return 0;                           /* is ignored                      */
#endif
}

SYS_SIG_T       syAnswerTstp ( signr )
    int                 signr;
{
    syStopraw( syFid );
    signal( SIGCONT, syAnswerCont );
    kill( getpid(), SIGTSTP );
#ifdef SYS_HAS_SIG_T
    return 0;                           /* is ignored                      */
#endif
}

#endif

int             syStartraw ( fid )
    long                fid;
{
    /* if running under a window handler, tell it that we want to read     */
    if ( syWindow ) {
        if      ( fid == 0 ) { syWinPut( fid, "@i", "" );  return 1; }
        else if ( fid == 2 ) { syWinPut( fid, "@e", "" );  return 1; }
        else {                                             return 0; }
    }

    /* try to get the terminal attributes, will fail if not terminal       */
    if ( ioctl( fileno(syBuf[fid].fp), TIOCGETP, (char*)&syOld ) == -1 )
        return 0;

    /* disable interrupt, quit, start and stop output characters           */
    if ( ioctl( fileno(syBuf[fid].fp), TIOCGETC, (char*)&syOldT ) == -1 )
        return 0;
    syNewT = syOldT;
    syNewT.t_intrc  = -1;
    syNewT.t_quitc  = -1;
    /*C 27-Nov-90 martin changing '<ctr>S' and '<ctr>Q' does not work      */
    /*C syNewT.t_startc = -1;                                              */
    /*C syNewT.t_stopc  = -1;                                              */
    if ( ioctl( fileno(syBuf[fid].fp), TIOCSETC, (char*)&syNewT ) == -1 )
        return 0;

    /* disable input buffering, line editing and echo                      */
    syNew = syOld;
    syNew.sg_flags |= CBREAK;
    syNew.sg_flags &= ~ECHO;
    if ( ioctl( fileno(syBuf[fid].fp), TIOCSETN, (char*)&syNew ) == -1 )
        return 0;

#ifdef SIGTSTP
    /* install signal handler for stop                                     */
    syFid = fid;
    signal( SIGTSTP, syAnswerTstp );
#endif

    /* indicate success                                                    */
    return 1;
}

void            syStopraw ( fid )
    long                fid;
{
    /* if running under a window handler, don't do nothing                 */
    if ( syWindow )
        return;

#ifdef SIGTSTP
    /* remove signal handler for stop                                      */
    signal( SIGTSTP, SIG_DFL );
#endif

    /* enable input buffering, line editing and echo again                 */
    if ( ioctl( fileno(syBuf[fid].fp), TIOCSETN, (char*)&syOld ) == -1 )
        fputs("gap: 'ioctl' could not turn off raw mode!\n",stderr);

    /* enable interrupt, quit, start and stop output characters again      */
    if ( ioctl( fileno(syBuf[fid].fp), TIOCSETC, (char*)&syOldT ) == -1 )
        fputs("gap: 'ioctl' could not turn off raw mode!\n",stderr);
}

int             syGetch ( fid )
    long                fid;
{
    char                ch;

    /* read a character                                                    */
    while ( read( fileno(syBuf[fid].fp), &ch, 1 ) != 1 || ch == '\0' )
        ;

    /* if running under a window handler, handle special characters        */
    if ( syWindow && ch == '@' ) {
        do {
            while ( read(fileno(syBuf[fid].fp), &ch, 1) != 1 || ch == '\0' )
                ;
        } while ( ch < '@' || 'z' < ch );
        if ( ch == 'y' ) {
            syWinPut( fileno(syBuf[fid].echo), "@s", "" );
            ch = syGetch(fid);
        }
        else if ( 'A' <= ch && ch <= 'Z' )
            ch = CTR(ch);
    }

    /* return the character                                                */
    return ch;
}

void            syEchoch ( ch, fid )
    int                 ch;
    long                fid;
{
    char                ch2;

    /* write the character to the associate echo output device             */
    ch2 = ch;
    write( fileno(syBuf[fid].echo), (char*)&ch2, 1 );

    /* if running under a window handler, duplicate '@'                    */
    if ( syWindow && ch == '@' ) {
        ch2 = ch;
        write( fileno(syBuf[fid].echo), (char*)&ch2, 1 );
    }
}

void            syEchos ( str, fid )
    char *              str;
    long                fid;
{
    /* if running under a window handler, send the line to it              */
    if ( syWindow && fid < 4 )
        syWinPut( fid, (fid == 1 ? "@n" : "@f"), str );

    /* otherwise, write it to the associate echo output device             */
    else
        write( fileno(syBuf[fid].echo), str, SyStrlen(str) );
}

#endif


/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
**
**  For UNIX System V, input/output redirection and typeahead are  supported.
**  We  turn off input buffering  and canonical input editing and  also echo.
**  Because we leave the signals enabled  we  have  to disable the characters
**  for interrupt and quit, which are usually set to '<ctr>-C' and '<ctr>-B'.
**  We   also turn off the  xon/xoff  start  and  stop  characters, which are
**  usually set to  '<ctr>-S'  and '<ctr>-Q' so we  can get those characters.
**  We do  not turn of  signals  'ISIG' because  we want   to catch  stop and
**  continue signals if this particular version  of UNIX supports them, so we
**  can turn the terminal line back to cooked mode before stopping GAP.
*/
#if SYS_USG

#ifndef SYS_TERMIO_H                    /* terminal control functions      */
# include       <termio.h>
# define SYS_TERMIO_H
#endif
#ifndef SYS_HAS_IOCTL_PROTO             /* UNIX decl. from 'man'           */
extern  int             ioctl P(( int, int, struct termio * ));
#endif

struct termio   syOld, syNew;           /* old and new terminal state      */

#ifndef SYS_SIGNAL_H                    /* signal handling functions       */
# include       <signal.h>
# ifdef SYS_HAS_SIG_T
#  define SYS_SIG_T     SYS_HAS_SIG_T
# else
#  define SYS_SIG_T     void
# endif
# define SYS_SIGNAL_H
typedef SYS_SIG_T       sig_handler_t P(( int ));
#endif
#ifndef SYS_HAS_SIGNAL_PROTO            /* ANSI/TRAD decl. from H&S 19.6   */
extern  sig_handler_t * signal P(( int, sig_handler_t * ));
extern  int             getpid P(( void ));
extern  int             kill P(( int, int ));
#endif

#ifndef SYS_HAS_READ_PROTO              /* UNIX decl. from 'man'           */
extern  int             read P(( int, char *, int ));
extern  int             write P(( int, char *, int ));
#endif

#ifdef SIGTSTP

long            syFid;

SYS_SIG_T       syAnswerCont ( signr )
    int                 signr;
{
    syStartraw( syFid );
    signal( SIGCONT, SIG_DFL );
    kill( getpid(), SIGCONT );
#ifdef SYS_HAS_SIG_T
    return 0;                           /* is ignored                      */
#endif
}

SYS_SIG_T       syAnswerTstp ( signr )
    int                 signr;
{
    syStopraw( syFid );
    signal( SIGCONT, syAnswerCont );
    kill( getpid(), SIGTSTP );
#ifdef SYS_HAS_SIG_T
    return 0;                           /* is ignored                      */
#endif
}

#endif

int             syStartraw ( fid )
    long                fid;
{
    /* if running under a window handler, tell it that we want to read     */
    if ( syWindow ) {
        if      ( fid == 0 ) { syWinPut( fid, "@i", "" );  return 1; }
        else if ( fid == 2 ) { syWinPut( fid, "@e", "" );  return 1; }
        else {                                             return 0; }
    }

    /* try to get the terminal attributes, will fail if not terminal       */
    if ( ioctl( fileno(syBuf[fid].fp), TCGETA, &syOld ) == -1 )   return 0;

    /* disable interrupt, quit, start and stop output characters           */
    syNew = syOld;
    syNew.c_cc[VINTR] = 0377;
    syNew.c_cc[VQUIT] = 0377;
    /*C 27-Nov-90 martin changing '<ctr>S' and '<ctr>Q' does not work      */
    /*C syNew.c_iflag    &= ~(IXON|INLCR|ICRNL);                           */
    syNew.c_iflag    &= ~(INLCR|ICRNL);

    /* disable input buffering, line editing and echo                      */
    syNew.c_cc[VMIN]  = 1;
    syNew.c_cc[VTIME] = 0;
    syNew.c_lflag    &= ~(ECHO|ICANON);
    if ( ioctl( fileno(syBuf[fid].fp), TCSETAW, &syNew ) == -1 )  return 0;

#ifdef SIGTSTP
    /* install signal handler for stop                                     */
    syFid = fid;
    signal( SIGTSTP, syAnswerTstp );
#endif

    /* indicate success                                                    */
    return 1;
}

void            syStopraw ( fid )
    long                fid;
{
    /* if running under a window handler, don't do nothing                 */
    if ( syWindow )
        return;

#ifdef SIGTSTP
    /* remove signal handler for stop                                      */
    signal( SIGTSTP, SIG_DFL );
#endif

    /* enable input buffering, line editing and echo again                 */
    if ( ioctl( fileno(syBuf[fid].fp), TCSETAW, &syOld ) == -1 )
        fputs("gap: 'ioctl' could not turn off raw mode!\n",stderr);
}

int             syGetch ( fid )
    long                fid;
{
    char                ch;

    /* read a character                                                    */
    while ( read( fileno(syBuf[fid].fp), &ch, 1 ) != 1 || ch == '\0' )
        ;

    /* if running under a window handler, handle special characters        */
    if ( syWindow && ch == '@' ) {
        do {
            while ( read(fileno(syBuf[fid].fp), &ch, 1) != 1 || ch == '\0' )
                ;
        } while ( ch < '@' || 'z' < ch );
        if ( ch == 'y' ) {
            syWinPut( fileno(syBuf[fid].echo), "@s", "" );
            ch = syGetch(fid);
        }
        else if ( 'A' <= ch && ch <= 'Z' )
            ch = CTR(ch);
    }

    /* return the character                                                */
    return ch;
}

void            syEchoch ( ch, fid )
    int                 ch;
    long                fid;
{
    char                ch2;

    /* write the character to the associate echo output device             */
    ch2 = ch;
    write( fileno(syBuf[fid].echo), (char*)&ch2, 1 );

    /* if running under a window handler, duplicate '@'                    */
    if ( syWindow && ch == '@' ) {
        ch2 = ch;
        write( fileno(syBuf[fid].echo), (char*)&ch2, 1 );
    }
}

void            syEchos ( str, fid )
    char *              str;
    long                fid;
{
    /* if running under a window handler, send the line to it              */
    if ( syWindow && fid < 4 )
        syWinPut( fid, (fid == 1 ? "@n" : "@f"), str );

    /* otherwise, write it to the associate echo output device             */
    else
        write( fileno(syBuf[fid].echo), str, SyStrlen(str) );
}

#endif


/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
**
**  OS/2 is almost the same as UNIX System V, except for function keys.
*/
#if SYS_OS2_EMX

#ifndef SYS_TERMIO_H                    /* terminal control functions      */
# include       <termio.h>
# define SYS_TERMIO_H
#endif
#ifndef SYS_HAS_IOCTL_PROTO             /* UNIX decl. from 'man'           */
extern  int             ioctl P(( int, int, struct termio * ));
#endif

struct termio   syOld, syNew;           /* old and new terminal state      */

#ifndef SYS_SIGNAL_H                    /* signal handling functions       */
# include       <signal.h>
# ifdef SYS_HAS_SIG_T
#  define SYS_SIG_T     SYS_HAS_SIG_T
# else
#  define SYS_SIG_T     void
# endif
# define SYS_SIGNAL_H
typedef SYS_SIG_T       sig_handler_t P(( int ));
#endif
#ifndef SYS_HAS_SIGNAL_PROTO            /* ANSI/TRAD decl. from H&S 19.6   */
extern  sig_handler_t * signal P(( int, sig_handler_t * ));
extern  int             getpid P(( void ));
extern  int             kill P(( int, int ));
#endif

#ifndef SYS_HAS_READ_PROTO              /* UNIX decl. from 'man'           */
extern  int             read P(( int, char *, int ));
extern  int             write P(( int, char *, int ));
#endif

#ifdef SIGTSTP

long            syFid;

SYS_SIG_T       syAnswerCont ( signr )
    int                 signr;
{
    syStartraw( syFid );
    signal( SIGCONT, SIG_DFL );
    kill( getpid(), SIGCONT );
#ifdef SYS_HAS_SIG_T
    return 0;                           /* is ignored                      */
#endif
}

SYS_SIG_T       syAnswerTstp ( signr )
    int                 signr;
{
    syStopraw( syFid );
    signal( SIGCONT, syAnswerCont );
    kill( getpid(), SIGTSTP );
#ifdef SYS_HAS_SIG_T
    return 0;                           /* is ignored                      */
#endif
}

#endif

int             syStartraw ( fid )
    long                fid;
{
    /* if running under a window handler, tell it that we want to read     */
    if ( syWindow ) {
        if      ( fid == 0 ) { syWinPut( fid, "@i", "" );  return 1; }
        else if ( fid == 2 ) { syWinPut( fid, "@e", "" );  return 1; }
        else {                                             return 0; }
    }

    /* try to get the terminal attributes, will fail if not terminal       */
    if ( ioctl( fileno(syBuf[fid].fp), TCGETA, &syOld ) == -1 )   return 0;

    /* disable interrupt, quit, start and stop output characters           */
    syNew = syOld;
    syNew.c_cc[VINTR] = 0377;
    syNew.c_cc[VQUIT] = 0377;
    /*C 27-Nov-90 martin changing '<ctr>S' and '<ctr>Q' does not work      */
    /*C syNew.c_iflag    &= ~(IXON|INLCR|ICRNL);                           */
    syNew.c_iflag    &= ~(INLCR|ICRNL);

    /* disable input buffering, line editing and echo                      */
    syNew.c_cc[VMIN]  = 1;
    syNew.c_cc[VTIME] = 0;
    syNew.c_lflag    &= ~(ECHO|ICANON|IDEFAULT);
    if ( ioctl( fileno(syBuf[fid].fp), TCSETAW, &syNew ) == -1 )  return 0;

#ifdef SIGTSTP
    /* install signal handler for stop                                     */
    syFid = fid;
    signal( SIGTSTP, syAnswerTstp );
#endif

    /* indicate success                                                    */
    return 1;
}

void            syStopraw ( fid )
    long                fid;
{
    /* if running under a window handler, don't do nothing                 */
    if ( syWindow )
        return;

#ifdef SIGTSTP
    /* remove signal handler for stop                                      */
    signal( SIGTSTP, SIG_DFL );
#endif

    /* enable input buffering, line editing and echo again                 */
    if ( ioctl( fileno(syBuf[fid].fp), TCSETAW, &syOld ) == -1 )
        fputs("gap: 'ioctl' could not turn off raw mode!\n",stderr);
}

#ifndef SYS_KBD_H                       /* keyboard scan codes             */
# include       <sys/kbdscan.h>
# define SYS_KBD_H
#endif

int             syGetch ( fid )
    long                fid;
{
    unsigned char       ch;
    int                 ch2;

syGetchAgain:
    /* read a character                                                    */
    while ( read( fileno(syBuf[fid].fp), &ch, 1 ) != 1 )
        ;

    /* if running under a window handler, handle special characters        */
    if ( syWindow && ch == '@' ) {
        do {
            while ( read(fileno(syBuf[fid].fp), &ch, 1) != 1 )
                ;
        } while ( ch < '@' || 'z' < ch );
        if ( ch == 'y' ) {
            syWinPut( fileno(syBuf[fid].echo), "@s", "" );
            ch = syGetch(fid);
        }
        else if ( 'A' <= ch && ch <= 'Z' )
            ch = CTR(ch);
    }

    ch2 = ch;

    /* handle function keys                                                */
    if ( ch == '\0' ) {
        while ( read( fileno(syBuf[fid].fp), &ch, 1 ) != 1 )
            ;
        switch ( ch ) {
        case K_LEFT:            ch2 = CTR('B');  break;
        case K_RIGHT:           ch2 = CTR('F');  break;
        case K_UP:
        case K_PAGEUP:          ch2 = CTR('P');  break;
        case K_DOWN:
        case K_PAGEDOWN:        ch2 = CTR('N');  break;
        case K_DEL:             ch2 = CTR('D');  break;
        case K_HOME:            ch2 = CTR('A');  break;
        case K_END:             ch2 = CTR('E');  break;
        case K_CTRL_END:        ch2 = CTR('K');  break;
        case K_CTRL_LEFT:
        case K_ALT_B:           ch2 = ESC('B');  break;
        case K_CTRL_RIGHT:
        case K_ALT_F:           ch2 = ESC('F');  break;
        case K_ALT_D:           ch2 = ESC('D');  break;
        case K_ALT_DEL:
        case K_ALT_BACKSPACE:   ch2 = ESC(127);  break;
        case K_ALT_U:           ch2 = ESC('U');  break;
        case K_ALT_L:           ch2 = ESC('L');  break;
        case K_ALT_C:           ch2 = ESC('C');  break;
        case K_CTRL_PAGEUP:     ch2 = ESC('<');  break;
        case K_CTRL_PAGEDOWN:   ch2 = ESC('>');  break;
        default:                goto syGetchAgain;
        }
    }

    /* return the character                                                */
    return ch2;
}

void            syEchoch ( ch, fid )
    int                 ch;
    long                fid;
{
    char                ch2;

    /* write the character to the associate echo output device             */
    ch2 = ch;
    write( fileno(syBuf[fid].echo), (char*)&ch2, 1 );

    /* if running under a window handler, duplicate '@'                    */
    if ( syWindow && ch == '@' ) {
        ch2 = ch;
        write( fileno(syBuf[fid].echo), (char*)&ch2, 1 );
    }
}

void            syEchos ( str, fid )
    char *              str;
    long                fid;
{
    /* if running under a window handler, send the line to it              */
    if ( syWindow && fid < 4 )
        syWinPut( fid, (fid == 1 ? "@n" : "@f"), str );

    /* otherwise, write it to the associate echo output device             */
    else
        write( fileno(syBuf[fid].echo), str, SyStrlen(str) );
}

#endif


/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
**
**  For MS-DOS we read directly from the keyboard.
**  Note that the window handler is not currently supported.
*/
#if SYS_MSDOS_DJGPP

#ifndef SYS_KBD_H                       /* keyboard functions              */
# include       <pc.h>
# define GETKEY()       getkey()
# define PUTCHAR(C)     putchar(C)
# define KBHIT()        kbhit()
# define SYS_KBD_H
#endif

unsigned long   syStopout;              /* output is stopped by <ctr>-'S'  */

char            syTypeahead [256];      /* characters read by 'SyIsIntr'   */

char            syAltMap [35] = "QWERTYUIOP    ASDFGHJKL     ZXCVBNM";

int             syStartraw ( fid )
    long                fid;
{
    /* check if the file is a terminal                                     */
    if ( ! isatty( fileno(syBuf[fid].fp) ) )
        return 0;

    /* indicate success                                                    */
    return 1;
}

void            syStopraw ( fid )
    long                fid;
{
}

int             syGetch ( fid )
    long                fid;
{
    int                 ch;

    /* if chars have been typed ahead and read by 'SyIsIntr' read them     */
    if ( syTypeahead[0] != '\0' ) {
        ch = syTypeahead[0];
        strcpy( syTypeahead, syTypeahead+1 );
    }

    /* otherwise read from the keyboard                                    */
    else {
        ch = GETKEY();
    }

    /* postprocess the character                                           */
    if ( 0x110 <= ch && ch <= 0x132 )   ch = ESC( syAltMap[ch-0x110] );
    else if ( ch == 0x147 )             ch = CTR('A');
    else if ( ch == 0x14f )             ch = CTR('E');
    else if ( ch == 0x148 )             ch = CTR('P');
    else if ( ch == 0x14b )             ch = CTR('B');
    else if ( ch == 0x14d )             ch = CTR('F');
    else if ( ch == 0x150 )             ch = CTR('N');
    else if ( ch == 0x153 )             ch = CTR('D');
    else                                ch &= 0xFF;

    /* return the character                                                */
    return ch;
}

void            syEchoch ( ch, fid )
    int                 ch;
    long                fid;
{
    PUTCHAR( ch );
}

void            syEchos ( str, fid )
    char *              str;
    long                fid;
{
    char *              s;

    /* handle stopped output                                               */
    while ( syStopout )  syStopout = (GETKEY() == CTR('S'));

    /* echo the string                                                     */
    for ( s = str; *s != '\0'; s++ )
        PUTCHAR( *s );
}

#endif


/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
**
**  For TOS we read directly from the keyboard.
**  Note that the window handler is not currently supported.
*/
#if SYS_TOS_GCC2

#ifndef SYS_KBD_H                       /* keyboard functions              */
# include       <unixlib.h>             /* declaration of 'isatty'         */
# include       <osbind.h>              /* operating system binding        */
# define GETKEY()       Bconin( 2 )
# define PUTCHAR(C)     do{if(C=='\n')Bconout(2,'\r');Bconout(2,C);}while(0)
# define KBHIT()        Bconstat( 2 )
# define SYS_KBD_H
#endif

unsigned long   syStopout;              /* output is stopped by <ctr>-'S'  */

char            syTypeahead [256];      /* characters read by 'SyIsIntr'   */

int             syStartraw ( fid )
    long                fid;
{
    /* check if the file is a terminal                                     */
    if ( ! isatty( fileno(syBuf[fid].fp) ) )
        return 0;

    /* indicate success                                                    */
    return 1;
}

void            syStopraw ( fid )
    long                fid;
{
}

int             syGetch ( fid )
    long                fid;
{
    int                 ch;

    /* if chars have been typed ahead and read by 'SyIsIntr' read them     */
    if ( syTypeahead[0] != '\0' ) {
        ch = syTypeahead[0];
        strcpy( syTypeahead, syTypeahead+1 );
    }

    /* otherwise read from the keyboard                                    */
    else {
        ch = GETKEY();
    }

    /* postprocess the character                                           */
    if (      ch == 0x00480000 )        ch = CTR('P');
    else if ( ch == 0x004B0000 )        ch = CTR('B');
    else if ( ch == 0x004D0000 )        ch = CTR('F');
    else if ( ch == 0x00500000 )        ch = CTR('N');
    else if ( ch == 0x00730000 )        ch = CTR('Y');
    else if ( ch == 0x00740000 )        ch = CTR('Z');
    else                                ch = ch & 0xFF;

    /* return the character                                                */
    return ch;
}

void            syEchoch ( ch, fid )
    int                 ch;
    long                fid;
{
    PUTCHAR( ch );
}

void            syEchos ( str, fid )
    char *              str;
    long                fid;
{
    char *              s;

    /* handle stopped output                                               */
    while ( syStopout )  syStopout = (GETKEY() == CTR('S'));

    /* echo the string                                                     */
    for ( s = str; *s != '\0'; s++ )
        PUTCHAR( *s );
}

#endif


/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
**
**  For VMS we use a virtual keyboard to read and  write from the unique tty.
**  We do not support the window handler.
*/
#if SYS_VMS

#ifndef SYS_HAS_MISC_PROTO              /* UNIX decl. from 'man'           */
extern  int             isatty P(( int ));
#endif

unsigned int            syVirKbd;       /* virtual (raw) keyboard          */

int             syStartraw ( fid )
    long                fid;
{
    /* test whether the file is connected to a terminal                    */
    return isatty( fileno(syBuf[fid].fp) );
}

void            syStopraw ( fid )
    long                fid;
{
}

int             syGetch ( fid )
    long                fid;
{
    char                ch;

    /* read a character                                                    */
    smg$read_keystroke( &syVirKbd, &ch );

    /* return the character                                                */
    return ch;
}

void            syEchoch ( ch, fid )
    int                 ch;
    long                fid;
{
    char                ch2;

    /* write the character to the associate echo output device             */
    ch2 = ch;
    write( fileno(syBuf[fid].echo), (char*)&ch2, 1 );
}

void            syEchos ( str, fid )
    char *              str;
    long                fid;
{
    write( fileno(syBuf[fid].echo), str, SyStrlen(str) );
}

#endif


/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
**
**  For the MAC with MPW we do not really know how to do this.
*/
#if SYS_MAC_MPW

int             syStartraw ( fid )
    long                fid;
{
    /* clear away pending <command>-'.'                                    */
    SyIsIntr();

    return 0;
}

void            syStopraw ( fid )
    long                fid;
{
}

int             syGetch ( fid )
    long                fid;
{
}

void            syEchoch ( ch, fid )
    int                 ch;
    long                fid;
{
}

void            syEchos ( str, fid )
    char *              str;
    long                fid;
{
    char *              s;
    for ( s = str; *s != '\0'; s++ )
        putchar( *s );
    fflush( stdout );
}

#endif


/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
**
**  For the MAC with Symantec C we use the console input/output package.
**  We must set the console to raw mode and back to echo mode.
**  In raw mode there is no cursor, so we reverse the current character.
*/
#if SYS_MAC_SYC

#ifndef SYS_UNIX_H                      /* unix stuff:                     */
# include       <unix.h>                /* 'isatty'                        */
# define SYS_UNIX_H
#endif

#ifndef SYS_CONSOLE_H                   /* console stuff:                  */
# include       <Console.h>             /* 'csetmode'                      */
# define SYS_CONSOLE_H
#endif

#ifndef SYS_OSUTILS_H                   /* system utils:                   */
# include       <OSUtils.h>             /* 'SysBeep'                       */
# define SYS_OSUTILS_H
#endif

int             syStartraw ( fid )
    long                fid;
{

    /* cannot switch ordinary files to raw mode                            */
    if ( ! isatty( fileno(syBuf[fid].fp) ) )
        return 0;

    /* turn terminal to raw mode                                           */
    csetmode( C_RAW, syBuf[fid].fp );
    return 1;
}

void            syStopraw ( fid )
    long                fid;
{
    /* probably only paranoid                                              */
    if ( isatty( fileno(syBuf[fid].fp) ) )
        return;

    /* turn terminal back to echo mode                                     */
    csetmode( C_ECHO, syBuf[fid].fp );
}

int             syGetch ( fid )
    long                fid;
{
    /* return character                                                    */
    return syGetch2( fid, '\0' );
}

int             syGetch2 ( fid, cur )
    long                fid;
    int                 cur;
{
    int                 ch;

    /* probably only paranoid                                              */
    if ( ! isatty( fileno(syBuf[fid].fp) ) )
        return EOF;

    /* make the current character reverse to simulate a cursor             */
    syEchoch( (cur != '\0' ? cur : ' ') | 0x80, fid );
    syEchoch( '\b', fid );

    /* get a character, ignore EOF and chars beyond 0x7F (reverse video)   */
    while ( ((ch = getchar()) == EOF) || (0x7F < ch) )
        ;

    /* handle special characters                                           */
    if (      ch == 28 )  ch = CTR('B');
    else if ( ch == 29 )  ch = CTR('F');
    else if ( ch == 30 )  ch = CTR('P');
    else if ( ch == 31 )  ch = CTR('N');

    /* make the current character normal again                             */
    syEchoch( (cur != '\0' ? cur : ' '), fid );
    syEchoch( '\b', fid );

    /* return the character                                                */
    return ch;
}

void            syEchoch ( ch, fid )
    int                 ch;
    long                fid;
{

    /* probably only paranoid                                              */
    if ( ! isatty( fileno(syBuf[fid].fp) ) )
        return;

    /* echo the character                                                  */
    if ( 31 < (ch & 0x7F) || ch == '\b' || ch == '\n' || ch == '\r' )
        putchar( ch );
    else if ( ch == CTR('G') )
        SysBeep( 1 );
    else
        putchar( '?' );

}

void            syEchos ( str, fid )
    char *              str;
    long                fid;
{
    char *              s;

    /* probably only paranoid                                              */
    if ( ! isatty( fileno(syBuf[fid].fp) ) )
        return;

    /* print the string                                                    */
    for ( s = str; *s != '\0'; s++ )
        putchar( *s );

}

#endif


/****************************************************************************
**
*F  SyFputs( <line>, <fid> )  . . . . . . . .  write a line to the file <fid>
**
**  'SyFputs' is called to put the  <line>  to the file identified  by <fid>.
*/
#if SYS_BSD || SYS_MACH || SYS_USG || SYS_OS2_EMX || SYS_VMS || SYS_MAC_MPW || SYS_MAC_SYC

void            SyFputs ( line, fid )
    char                line [];
    long                fid;
{
    long                i;

    /* if outputing to the terminal compute the cursor position and length */
    if ( fid == 1 || fid == 3 ) {
        syNrchar = 0;
        for ( i = 0; line[i] != '\0'; i++ ) {
            if ( line[i] == '\n' )  syNrchar = 0;
            else                    syPrompt[syNrchar++] = line[i];
        }
        syPrompt[syNrchar] = '\0';
    }

    /* otherwise compute only the length                                   */
    else {
        for ( i = 0; line[i] != '\0'; i++ )
            ;
    }

    /* if running under a window handler, send the line to it              */
    if ( syWindow && fid < 4 )
        syWinPut( fid, (fid == 1 ? "@n" : "@f"), line );

    /* otherwise, write it to the output file                              */
    else
#if ! (SYS_MAC_MPW || SYS_MAC_SYC)
        write( fileno(syBuf[fid].fp), line, i );
#endif
#if SYS_MAC_MPW || SYS_MAC_SYC
        fputs( line, syBuf[fid].fp );
#endif
}

#endif

#if SYS_MSDOS_DJGPP || SYS_TOS_GCC2

void            SyFputs ( line, fid )
    char                line [];
    long                fid;
{
    long                i;
    char *              s;

    /* handle the console                                                  */
    if ( isatty( fileno(syBuf[fid].fp) ) ) {

        /* test whether this is a line with a prompt                       */
        syNrchar = 0;
        for ( i = 0; line[i] != '\0'; i++ ) {
            if ( line[i] == '\n' )  syNrchar = 0;
            else                    syPrompt[syNrchar++] = line[i];
        }
        syPrompt[syNrchar] = '\0';

        /* handle stopped output                                           */
        while ( syStopout )  syStopout = (GETKEY() == CTR('S'));

        /* output the line                                                 */
        for ( s = line; *s != '\0'; s++ )
            PUTCHAR( *s );
    }

    /* ordinary file                                                       */
    else {
        fputs( line, syBuf[fid].fp );
    }

}

#endif


/****************************************************************************
**
*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'.
*/
#if ! (SYS_MAC_MPW || SYS_MAC_SYC)

void            syWinPut ( fid, cmd, str )
    long                fid;
    char *              cmd;
    char *              str;
{
    long                fd;             /* file descriptor                 */
    char                tmp [130];      /* temporary buffer                */
    char *              s;              /* pointer into the string         */
    char *              t;              /* pointer into the temporary      */

    /* if not running under a window handler, don't do nothing             */
    if ( ! syWindow || 4 <= fid )
        return;

    /* get the file descriptor                                             */
    if ( fid == 0 || fid == 2 )  fd = fileno(syBuf[fid].echo);
    else                         fd = fileno(syBuf[fid].fp);

    /* print the cmd                                                       */
    write( fd, cmd, SyStrlen(cmd) );

    /* print the output line, duplicate '@' and handle <ctr>-<chr>         */
    s = str;  t = tmp;
    while ( *s != '\0' ) {
        if ( *s == '@' ) {
            *t++ = '@';  *t++ = *s++;
        }
        else if ( CTR('A') <= *s && *s <= CTR('Z') ) {
            *t++ = '@';  *t++ = *s++ - CTR('A') + 'A';
        }
        else {
            *t++ = *s++;
        }
        if ( 128 <= t-tmp ) {
            write( fd, tmp, t-tmp );
            t = tmp;
        }
    }
    if ( 0 < t-tmp ) {
        write( fd, tmp, t-tmp );
    }
}

#endif

#if SYS_MAC_MPW || SYS_MAC_SYC

void            syWinPut ( fid, cmd, str )
    long                fid;
    char *              cmd;
    char *              str;
{
}

#endif


/****************************************************************************
**
*F  SyPinfo( <nr>, <size> ) . . . . . . . . . . . . . . .  print garbage info
**
**  'SyPinfo' is called from  Gasman to inform the  window handler  about the
**  current  Gasman   statistics.  <nr> determines   the   phase the  garbage
**  collection is currently  in, and <size>  is the correspoding value, e.g.,
**  number of live bags.
*/
void            SyPinfo ( nr, size )
    int                 nr;
    long                size;
{
    char                cmd [3];
    char                buf [16];
    char *              b;

    /* set up the command                                                  */
    cmd[0] = '@';
    cmd[1] = nr + '0';
    cmd[2] = '\0';

    /* stringify the argument                                              */
    b = buf;
    while ( 0 < size ) {
        *b++ = (size % 10) + '0';
        size /= 10;
    }
    *b++ = '+';
    *b = '\0';

    /* send it to the window handler                                       */
    syWinPut( 1, cmd, buf );
}


/****************************************************************************
**
*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.
*/
#if ! (SYS_MAC_MPW || SYS_MAC_SYC)

char            WinCmdBuffer [8000];

char *          SyWinCmd ( str,  len )
    char *              str;
    long                len;
{
    char                buf [130];      /* temporary buffer                */
    char *              s;              /* pointer into the string         */
    char *              b;              /* pointer into the temporary      */
    unsigned long       i;              /* loop variable                   */

    /* if not running under a window handler, don't do nothing             */
    if ( ! syWindow )
        return "I1+S52000000No Window Handler Present";

    /* compute the length of the (expanded) string (and ignore argument)   */
    len = 0;
    for ( s = str; *s != '\0'; s++ )
        len += 1 + (*s == '@' || (CTR('A') <= *s && *s <= CTR('Z')));

    /* send the length to the window handler                               */
    b = buf;
    for ( i = 0; i < 8; i++ ) {
        *b++ = (len % 10) + '0';
        len /= 10;
    }
    *b = '\0';
    syWinPut( 1, "@w", buf );

    /* send the string to the window handler                               */
    syWinPut( 1, "", str );

    /* read the length of the answer                                       */
    s = WinCmdBuffer;
    i = 10;
    do {
        while ( 0 < i ) {
            len = read( 0, s, i );
            i  -= len;
            s  += len;
        }
        if ( WinCmdBuffer[0] == '@' && WinCmdBuffer[1] == 'y' ) {
            for ( i = 2;  i < 10;  i++ )
                WinCmdBuffer[i-2] = WinCmdBuffer[i];
            s -= 2;
            i  = 2;
        }
    } while ( 0 < i );
    if ( WinCmdBuffer[0] != '@' || WinCmdBuffer[1] != 'a' )
        return "I1+S41000000Illegal Answer";
    for ( len = 0, i = 9;  1 < i;  i-- )
        len = len*10 + (WinCmdBuffer[i]-'0');

    /* read the arguments of the answer                                    */
    s = WinCmdBuffer;
    i = len;
    while ( 0 < i ) {
        len = read( 0, s, i );
        i  -= len;
        s  += len;
    }

    /* shrink '@@' into '@'                                                */
    for ( b = s = WinCmdBuffer;  0 < len;  len-- ) {
        if ( *s == '@' ) {
            s++;
            if ( *s == '@' )
                *b++ = '@';
            else if ( 'A' <= *s && *s <= 'Z' )
                *b++ = CTR(*s);
            s++;
        }
        else {
            *b++ = *s++;
        }
    }
    *b = 0;

    /* return the string                                                   */
    return WinCmdBuffer;
}

#endif

#if SYS_MAC_MPW || SYS_MAC_SYC

char *          SyWinCmd ( str,  len )
    char *              str;
    long                len;
{
    return 0;
}

#endif


/****************************************************************************
**
*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.
*/


/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
**
**  For  UNIX, OS/2  and VMS  we  install 'syAnswerIntr' to  answer interrupt
**  'SIGINT'.   If two interrupts  occur within 1 second 'syAnswerIntr' exits
**  GAP.
*/
#if SYS_BSD || SYS_MACH || SYS_USG || SYS_OS2_EMX || SYS_VMS

#ifndef SYS_SIGNAL_H                    /* signal handling functions       */
# include       <signal.h>
# ifdef SYS_HAS_SIG_T
#  define SYS_SIG_T     SYS_HAS_SIG_T
# else
#  define SYS_SIG_T     void
# endif
# define SYS_SIGNAL_H
typedef SYS_SIG_T       sig_handler_t P(( int ));
#endif
#ifndef SYS_HAS_SIGNAL_PROTO            /* ANSI/TRAD decl. from H&S 19.6   */
extern  sig_handler_t * signal P(( int, sig_handler_t * ));
extern  int             getpid P(( void ));
extern  int             kill P(( int, int ));
#endif

#ifndef SYS_TIME_H                      /* time functions                  */
# if SYS_VMS
#  include      <types.h>               /* declaration of type 'time_t'    */
# endif
# include       <time.h>
# define SYS_TIME_H
#endif
#ifndef SYS_HAS_TIME_PROTO              /* ANSI/TRAD decl. from H&S 18.1    */
# if SYS_ANSI
extern  time_t          time P(( time_t * buf ));
# else
extern  long            time P(( long * buf ));
# endif
#endif

unsigned long   syLastIntr;             /* time of the last interrupt      */

SYS_SIG_T       syAnswerIntr ( signr )
    int                 signr;
{
    unsigned long       nowIntr;

    /* get the current wall clock time                                     */
    nowIntr = time(0);

    /* if the last '<ctr>-C' was less than a second ago, exit GAP          */
    if ( syLastIntr && nowIntr-syLastIntr < 1 ) {
        fputs("gap: you hit '<ctr>-C' twice in a second, goodbye.\n",stderr);
        SyExit( 1 );
    }

    /* remember time of this interrupt                                     */
    syLastIntr = nowIntr;

    /* reinstall 'syAnswerIntr' as signal handler                          */
#if ! SYS_OS2_EMX
    signal( SIGINT, syAnswerIntr );
#else
    signal( signr, SIG_ACK );
#endif

#ifdef SYS_HAS_SIG_T
    return 0;                           /* is ignored                      */
#endif
}

long            SyIsIntr ()
{
    long        isIntr;

    isIntr = (syLastIntr != 0);
    syLastIntr = 0;
    return isIntr;
}

#endif


/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
**
**  In DOS we check the input queue to look for <ctr>-'C', chars read are put
**  on the 'osTypeahead' buffer. The buffer is flushed if <ctr>-'C' is found.
**  Actually with the current DOS extender we cannot trap  <ctr>-'C', because
**  the DOS extender does so already, so be use <ctr>-'Z' and <alt>-'C'.
**
**  In TOS we check the input queue to look for <ctr>-'C', chars read are put
**  on the 'osTypeahead' buffer. The buffer is flushed if <ctr>-'C' is found.
**  There is however a problem, if 2 or  more characters are pending (that is
**  waiting to be read by either 'SyIsIntr' or 'SyGetch') and the second is a
**  <ctr>-'C', GAP will be killed when 'SyIsIntr' or  'syGetch' tries to read
**  the first character.  Thus  if you typed ahead  and want to interrupt the
**  computation, wait some time to make sure that  the typed ahead characters
**  have been read by 'SyIsIntr' befor you hit <ctr>-'C'.
*/
#if SYS_MSDOS_DJGPP || SYS_TOS_GCC2

long            syIsIntrFreq = 20;

long            syIsIntrCount = 0;

long            SyIsIntr ()
{
    int         ch, i;

    /* don't check for interrupts every time 'SyIsIntr' is called          */
    if ( 0 < --syIsIntrCount )
        return 0;
    syIsIntrCount = syIsIntrFreq;

    /* check for interrupts stuff the rest in typeahead buffer             */
    if ( syLineEdit && KBHIT() ) {
        while ( KBHIT() ) {
            ch = GETKEY();
            if ( ch == CTR('C') || ch == CTR('Z') || ch == 0x12E ) {
                PUTCHAR('^'); PUTCHAR('C');
                syTypeahead[0] = '\0';
                syStopout = 0;
                return 1L;
            }
            else if ( ch == CTR('X') ) {
                PUTCHAR('^'); PUTCHAR('X');
                syTypeahead[0] = '\0';
                syStopout = 0;
            }
            else if ( ch == CTR('S') ) {
                syStopout = 1;
            }
            else if ( syStopout ) {
                syStopout = 0;
            }
            else {
                for ( i = 0; i < sizeof(syTypeahead)-1; ++i ) {
                    if ( syTypeahead[i] == '\0' ) {
                        PUTCHAR(ch);
                        syTypeahead[i] = ch;
                        syTypeahead[i+1] = '\0';
                        break;
                    }
                }
            }
        }
        return 0L;
    }
    return 0L;
}

#endif


/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
**
**  For a  MPW Tool, we install 'syAnswerIntr'  to answer interrupt 'SIGINT'.
**  However, the interrupt is  only delivered when  the system has a control,
**  namely  when  we call the  toolbox   function 'SpinCursor' in 'SyIsIntr'.
**  Thus the mechanism is effectively polling.
**
**  For a MPW SIOW, we search the event queue for a <cmd>-'.' or a <cnt>-'C'.
**  If one is found, all keyboard events are flushed.
**
*N  1995/04/30 mschoene these should be merged
*/
#if SYS_MAC_MPW

#ifdef  SYS_HAS_TOOL

#ifndef SYS_SIGNAL_H                    /* signal handling functions       */
# include       <Signal.h>
# ifdef SYS_HAS_SIG_T
#  define SYS_SIG_T     SYS_HAS_SIG_T
# else
#  define SYS_SIG_T     void
# endif
# define SYS_SIGNAL_H
typedef SYS_SIG_T       sig_handler_t P(( int ));
#endif
#ifndef SYS_HAS_SIGNAL_PROTO            /* ANSI/TRAD decl. from H&S 19.6   */
extern  sig_handler_t * signal P(( int, sig_handler_t * ));
#endif

#ifndef SYS_CURSORCTL_H                 /* cursor control functions:       */
# include       <CursorCtl.h>           /* 'Show_Cursor', 'SpinCursor'     */
# define SYS_CURSORCTL_H
#endif

unsigned long   syNrIntr;               /* number of interrupts            */

unsigned long   syLastIntr;             /* time of the last interrupt      */

long            syIsIntrFreq = 100;     /* frequency to test interrupts    */

long            syIsIntrCount =  0;     /* countdown to test interrupts    */

void            syAnswerIntr ( signr )
    int                 signr;
{
    /* reinstall the signal handler                                        */
    signal( SIGINT, &syAnswerIntr );

    /* exit if two interrupts happen within one second                     */
    /*N 1993/05/28 martin this doesn't work, because interrupts are only   */
    /*N                   delivered when we call 'SpinCursor' below        */
    if ( syNrIntr && SyTime()-syLastIntr <= 1000 )
        SyExit( 1 );

    /* got one more interrupt                                              */
    syNrIntr   = syNrIntr + 1;
    syLastIntr = SyTime();
}

long            SyIsIntr ()
{
    long                syIsIntr;

    /* don't check for interrupts every time 'SyIsIntr' is called          */
    if ( 0 < --syIsIntrCount )
        return 0;
    syIsIntrCount = syIsIntrFreq;

    /* spin the beachball                                                  */
    Show_Cursor( HIDDEN_CURSOR );
    SpinCursor( 8 );

    /* check for interrupts                                                */
    syIsIntr = (syNrIntr != 0);

    /* every interrupt leaves a <eof>, which we want to remove             */
    while ( syNrIntr ) {
        while ( getchar() != EOF ) ;
        clearerr( stdin );
        syNrIntr = syNrIntr - 1;
    }

    /* return whether an interrupt has happened                            */
    return syIsIntr;
}

#else

#ifndef SYS_TYPES_H                     /* various types                   */
# include       <Types.h>
# define SYS_TYPES_H
#endif

#ifndef SYS_OSUTILS_H                   /* system utils:                   */
# include       <OSUtils.h>             /* 'QHdr'                          */
# define SYS_OSUTILS_H
#endif

#ifndef SYS_OSEVENTS_H                  /* system events, low level:       */
# include       <OSEvents.h>            /* 'EvQEl', 'GetEvQHdr',           */
                                        /* 'FlushEvents'                   */
# define SYS_OSEVENTS_H
#endif

#ifndef SYS_EVENTS_H                    /* system events, high level:      */
# include       <Events.h>              /* 'EventRecord', 'GetNextEvent'   */
# define SYS_EVENTS_H
#endif

unsigned long   syNrIntr;               /* number of interrupts            */

unsigned long   syLastIntr;             /* time of the last interrupt      */

long            syIsIntrFreq = 100;     /* frequency to test interrupts    */

long            syIsIntrCount =  0;     /* countdown to test interrupts    */

long            SyIsIntr ()
{
    long                syIsIntr;
    struct QHdr *       queue;
    struct EvQEl *      qentry;

    /* don't check for interrupts every time 'SyIsIntr' is called          */
    if ( 0 < --syIsIntrCount )
        return 0;
    syIsIntrCount = syIsIntrFreq;

    /* look through the event queue for <command>-'.' or <control>-'C'     */
    queue = GetEvQHdr();
    qentry = (struct EvQEl *)(queue->qHead);
    while ( qentry ) {
        if ( qentry->evtQWhat == keyDown
            &&   ( ((qentry->evtQModifiers & controlKey) != 0)
                && ((qentry->evtQMessage & charCodeMask) ==   3))
              || ( ((qentry->evtQModifiers & cmdKey    ) != 0)
                && ((qentry->evtQMessage & charCodeMask) == '.')) ) {
            syNrIntr++;
        }
        qentry = (struct EvQEl *)(qentry->qLink);
    }

    /* check for interrupts                                                */
    syIsIntr = (syNrIntr != 0);

    /* flush away all keyboard events after an interrupt                   */
    if ( syNrIntr ) {
        FlushEvents( keyDownMask, 0 );
        syNrIntr = 0;
    }

    /* return whether an interrupt has happened                            */
    return syIsIntr;
}

#endif

#endif


/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
**
**  For Symantec C, we search the event queue for a <cmd>-'.' or a <cnt>-'C'.
**  If one is found, all keyboard events are flushed, and 'true' is returned.
**  We also  check for signals  just to  be safe.   Because signals are  only
**  delivered when the system is in control, e.g., when we call 'SystemTask',
**  there is no point to test for two interrupts within a second.
*/
#if SYS_MAC_SYC

#ifndef SYS_SIGNAL_H                    /* signal handling functions       */
# include       <signal.h>
# ifdef SYS_HAS_SIG_T
#  define SYS_SIG_T     SYS_HAS_SIG_T
# else
#  define SYS_SIG_T     void
# endif
# define SYS_SIGNAL_H
typedef SYS_SIG_T       sig_handler_t P(( int ));
#endif
#ifndef SYS_HAS_SIGNAL_PROTO            /* ANSI/TRAD decl. from H&S 19.6   */
extern  sig_handler_t * signal P(( int, sig_handler_t * ));
#endif

#ifndef SYS_TYPES_H                     /* various types                   */
# include       <Types.h>
# define SYS_TYPES_H
#endif

#ifndef SYS_LOWMEM_H                    /* variables in low memory:        */
# include       <LowMem.h>              /* 'LMGetTicks'                    */
# define SYS_LOWMEM_H
#endif

#ifndef SYS_OSUTILS_H                   /* system utils:                   */
# include       <OSUtils.h>             /* 'QHdr'                          */
# define SYS_OSUTILS_H
#endif

#ifndef SYS_OSEVENTS_H                  /* system events, low level:       */
# include       <OSEvents.h>            /* 'EvQEl', 'GetEvQHdr',           */
                                        /* 'FlushEvents'                   */
# define SYS_OSEVENTS_H
#endif

#ifndef SYS_EVENTS_H                    /* system events, high level:      */
# include       <Events.h>              /* 'EventRecord', 'GetNextEvent'   */
# define SYS_EVENTS_H
#endif

#ifndef SYS_LOMEM_H                     /* variables in low memory         */
# include       <LoMem.h>               /* 'SEvtEnb'                       */
# define SYS_LOMEM_H
#endif

#ifndef SYS_DESK_H
# include       <Desk.h>                /* 'SystemTask'                    */
# define SYS_DESK_H
#endif

unsigned long   syNrIntr;               /* number of interrupts            */

long            syIsIntrFreq  =  60;    /* frequency to test interrupts    */

long            syIsIntrCount =   0;    /* countdown to test interrupts    */

long            syIsBackFreq  = 600;    /* frequence background switching  */

long            syIsBackCount =   0;    /* countdown background switching  */

void            syAnswerIntr ( signr )
    int                 signr;
{
    /* reinstall the signal handler                                        */
    signal( SIGINT, &syAnswerIntr );

    /* got one more interrupt                                              */
    syNrIntr = syNrIntr + 1;
}

long            SyIsIntr ()
{
    long                syIsIntr;
    struct QHdr *       queue;
    struct EvQEl *      qentry;
    EventRecord         theEvent;

    /* don't check for interrupts every time 'SyIsIntr' is called          */
    if ( (*(long*)0x016A) <= syIsIntrCount )
        return 0;
    syIsIntrCount = (*(long*)0x016A) + syIsIntrFreq;

    /* allow for system activities                                         */
    if ( syIsBackCount < (*(long*)0x016A) ) {
        syIsBackCount = (*(long*)0x016A) + syIsBackFreq;
        SystemTask();
        SEvtEnb = false;
        GetNextEvent( activMask, &theEvent );
    }

    /* check for caught interrupts                                         */
    syIsIntr = (syNrIntr != 0);

    /* every caught interrupt leaves a <eof>, which we want to remove      */
    while ( syNrIntr ) {
        while ( getchar() != EOF ) ;
        clearerr( stdin );
        syNrIntr = syNrIntr - 1;
    }

    /* look through the event queue for <command>-'.' or <control>-'C'     */
    queue = GetEvQHdr();
    qentry = (struct EvQEl *)(queue->qHead);
    while ( qentry ) {
        if ( qentry->evtQWhat == keyDown
            &&   ( ((qentry->evtQModifiers & controlKey) != 0)
                && ((qentry->evtQMessage & charCodeMask) ==   3))
              || ( ((qentry->evtQModifiers & cmdKey    ) != 0)
                && ((qentry->evtQMessage & charCodeMask) == '.')) ) {
            syNrIntr++;
        }
        qentry = (struct EvQEl *)(qentry->qLink);
    }

    /* check for interrupts                                                */
    syIsIntr = syIsIntr || (syNrIntr != 0);

    /* flush away all keyboard events after an interrupt                   */
    if ( syNrIntr ) {
        FlushEvents( keyDownMask, 0 );
        syNrIntr = 0;
    }

    /* return whether an interrupt has happened                            */
    return syIsIntr;
}

#endif


/****************************************************************************
**
*F  SyExit( <ret> ) . . . . . . . . . . . . . exit GAP with return code <ret>
**
**  'SyExit' is the offical  way  to  exit GAP, bus errors are the inoffical.
**  The function 'SyExit' must perform all the neccessary cleanup operations.
**  If ret is 0 'SyExit' should signal to a calling proccess that all is  ok.
**  If ret is 1 'SyExit' should signal a  failure  to  the  calling proccess.
*/
#ifndef SYS_STDLIB_H                    /* ANSI standard functions         */
# if SYS_ANSI
#  include      <stdlib.h>
# endif
# define SYS_STDLIB_H
#endif
#ifndef SYS_HAS_MISC_PROTO              /* ANSI/TRAD decl. from H&S 19.3   */
extern  void            exit P(( int ));
#endif

#if SYS_MAC_SYC
#ifndef SYS_CONSOLE_H                   /* console stuff                   */
# include       <Console.h>             /* 'console_options'               */
# define SYS_CONSOLE_H
#endif
#endif

void            SyExit ( ret )
    long                ret;
{
#if SYS_MAC_MPW
# ifndef SYS_HAS_TOOL
    fputs("gap: please use <option>-'Q' to close the window.\n",stdout);
# endif
#endif

#if SYS_MAC_SYC
    /* if something went wrong, then give the user a change to see it      */
    if ( ret != 0 )
        console_options.pause_atexit = 1;

    /* if GAP will pause before exiting, tell the user                     */
    if ( console_options.pause_atexit == 1 )
        printf( "gap: enter <return> to exit");
#endif

    exit( (int)ret );
}


/****************************************************************************
**
*F  SyExec( <cmd> ) . . . . . . . . . . . execute command in operating system
**
**  'SyExec' executes the command <cmd> (a string) in the operating system.
**
**  'SyExec'  should call a command  interpreter  to execute the command,  so
**  that file name expansion and other common  actions take place.  If the OS
**  does not support this 'SyExec' should print a message and return.
**
**  For UNIX we can use 'system', which does exactly what we want.
*/
#ifndef SYS_STDLIB_H                    /* ANSI standard functions         */
# if SYS_ANSI
#  include      <stdlib.h>
# endif
# define SYS_STDLIB_H
#endif
#ifndef SYS_HAS_MISC_PROTO              /* ANSI/TRAD decl. from H&S 19.2   */
extern  int             system P(( SYS_CONST char * ));
#endif

#if ! (SYS_MAC_MPW || SYS_MAC_SYC)

void            SyExec ( cmd )
    char *              cmd;
{
    long                ignore;

    syWinPut( 0, "@z", "" );
    ignore = system( cmd );
    syWinPut( 0, "@mAgIc", "" );
}

#endif

#if SYS_MAC_MPW || SYS_MAC_SYC

void            SyExec ( cmd )
    char *              cmd;
{
}

#endif


/****************************************************************************
**
*F  SyTime()  . . . . . . . . . . . . . . . return time spent in milliseconds
**
**  'SyTime' returns the number of milliseconds spent by GAP so far.
**
**  Should be as accurate as possible,  because it  is  used  for  profiling.
*/


/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
**
**  For Berkeley UNIX the clock ticks in 1/60.  On some (all?) BSD systems we
**  can use 'getrusage', which gives us a much better resolution.
*/
#if SYS_BSD || SYS_MACH || SYS_MSDOS_DJGPP

#ifndef SYS_HAS_NO_GETRUSAGE

#ifndef SYS_RESOURCE_H                  /* definition of 'struct rusage'   */
# include       <sys/time.h>            /* definition of 'struct timeval'  */
# include       <sys/resource.h>
# define SYS_RESOURCE_H
#endif
#ifndef SYS_HAS_TIME_PROTO              /* UNIX decl. from 'man'           */
extern  int             getrusage P(( int, struct rusage * ));
#endif

unsigned long   SyTime ()
{
    struct rusage       buf;

    if ( getrusage( RUSAGE_SELF, &buf ) ) {
        fputs("gap: panic 'SyTime' cannot get time!\n",stderr);
        SyExit( 1 );
    }
    return buf.ru_utime.tv_sec*1000 + buf.ru_utime.tv_usec/1000 -syStartTime;
}

#endif

#ifdef SYS_HAS_NO_GETRUSAGE

#ifndef SYS_TIMES_H                     /* time functions                  */
# include       <sys/types.h>
# include       <sys/times.h>
# define SYS_TIMES_H
#endif
#ifndef SYS_HAS_TIME_PROTO              /* UNIX decl. from 'man'           */
extern  int             times P(( struct tms * ));
#endif

unsigned long   SyTime ()
{
    struct tms          tbuf;

    if ( times( &tbuf ) == -1 ) {
        fputs("gap: panic 'SyTime' cannot get time!\n",stderr);
        SyExit( 1 );
    }
    return 100 * tbuf.tms_utime / (60/10) - syStartTime;
}

#endif

#endif


/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
**
**  For UNIX System V and OS/2 the clock ticks in 1/HZ,  this is usually 1/60
**  or 1/100.
*/
#if SYS_USG || SYS_OS2_EMX

#ifndef SYS_TIMES_H                     /* time functions                  */
# include       <sys/param.h>           /* definition of 'HZ'              */
# include       <sys/types.h>
# include       <sys/times.h>
# define SYS_TIMES_H
#endif
#ifndef SYS_HAS_TIME_PROTO              /* UNIX decl. from 'man'           */
extern  int             times P(( struct tms * ));
#endif

unsigned long   SyTime ()
{
    struct tms          tbuf;

    if ( times( &tbuf ) == -1 ) {
        fputs("gap: panic 'SyTime' cannot get time!\n",stderr);
        SyExit( 1 );
    }
    return 100 * tbuf.tms_utime / (HZ / 10) - syStartTime;
}

#endif


/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
**
**  For TOS and VMS we use the function 'clock' and allow to stop the clock.
*/
#if SYS_TOS_GCC2 || SYS_VMS

#ifndef SYS_TIME_H                      /* time functions                  */
# include       <time.h>
# define SYS_TIME_H
#endif
#ifndef SYS_HAS_TIME_PROTO              /* ANSI/TRAD decl. from H&S 18.2    */
# if SYS_ANSI
extern  clock_t         clock P(( void ));
# define SYS_CLOCKS     CLOCKS_PER_SEC
# else
extern  long            clock P(( void ));
#  if SYS_TOS_GCC2
#   define SYS_CLOCKS   200
#  else
#   define SYS_CLOCKS   100
#  endif
# endif
#endif

unsigned long   SyTime ()
{
    return 100 * (unsigned long)clock() / (SYS_CLOCKS/10) - syStartTime;
}

#endif


/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
**
**  For  MAC with MPW we  use the 'TickCount' function  and allow to stop the
**  clock.
*/
#if SYS_MAC_MPW || SYS_MAC_SYC

#ifndef SYS_TYPES_H                     /* various types                   */
# include       <Types.h>
# define SYS_TYPES_H
#endif

#ifndef SYS_EVENTS_H                    /* system events, high level:      */
# include       <Events.h>              /* 'TickCount'                     */
# define SYS_EVENTS_H
#endif

unsigned long   SyTime ()
{
    return 100 * (unsigned long)TickCount() / (60/10) - syStartTime;
}

#endif


/****************************************************************************
**
*F  SyTmpname() . . . . . . . . . . . . . . . . . return a temporary filename
**
**  'SyTmpname' creates and returns a new temporary name.
*/
#ifndef SYS_STDIO_H                     /* standard input/output functions */
# include       <stdio.h>
# define SYS_STDIO_H
#endif
#ifndef SYS_HAS_MISC_PROTO              /* ANSI/TRAD decl. from H&S 15.16  */
extern  char *          tmpnam P(( char * ));
#endif

char *          SyTmpname ()
{
    return tmpnam( (char*)0 );
}


/****************************************************************************
**
*F  SyHelp( <topic>, <fid> )  . . . . . . . . . . . . . . display online help
**
**  This function is of course way to large.  But what the  heck,  it  works.
*/
char            syChapnames [128][16];

char            syLastTopics [16] [64] = { "Welcome to GAP" };

short           syLastIndex = 0;

void            SyHelp ( topic, fin )
    char *              topic;          /* topic for which help is sought  */
    long                fin;            /* file id of input and output     */
{
    char                filename [256]; /* filename of various files       */
    long                fid;            /* file identifier of various files*/
    char                line [256];     /* single line from those files    */
    unsigned long       chapnr;         /* number of the chapter           */
    char                chapname [64];  /* name of the chapter             */
    unsigned long       secnr;          /* number of the section           */
    char                secname [1024]; /* name of the section             */
    char                secline [128];  /* '\Section <secname>'            */
    long                match;          /* does the section match topic    */
    long                matches;        /* how many sections matched       */
    char                last [256];     /* last line from table of contents*/
    char                last2 [256];    /* last chapter line from toc      */
    long                offset;         /* '<' is -1, '>' is 1             */
    char                ch;             /* char read after '-- <space> --' */
    long                spaces;         /* spaces to be inserted for just  */
    char                status;         /* 'a', '$', '|', or '#'           */
    char                * p, * q, * r;  /* loop variables                  */
    unsigned long       i, j;           /* loop variables                  */
    unsigned long       raw;            /* is input in raw mode?           */

    /* try to switch the input into raw mode                               */
    raw = (syLineEdit == 1 && syStartraw( fin ));

    /* inform the window handler                                           */
    syWinPut( fin, "@h", "" );

    /* set 'SyHelpname' to 'SyLibname' with 'lib' replaced by 'doc'        */
    if ( SyHelpname[0] == '\0' ) {
        q = SyHelpname;
        p = SyLibname;
        while ( *p != '\0' )  *q++ = *p++;
        *q = '\0';
        for ( p = SyHelpname; *p != '\0'; p++ ) ;
        while ( SyHelpname < p && (p[0]!='l' || p[1]!='i' || p[2]!='b') )
            p--;
        p[0] = 'd'; p[1] = 'o'; p[2] = 'c';
    }

    /* skip leading blanks in the topic                                    */
    while ( *topic == ' ' )  topic++;

    /* if the topic is empty take the last one again                       */
    if ( topic[0] == '\0' ) {
        topic = syLastTopics[ syLastIndex ];
    }

    /* if the topic is '<' we are interested in the one before 'LastTopic' */
    offset = 0;
    last[0] = '\0';
    if ( SyStrcmp( topic, "<" ) == 0 ) {
        topic = syLastTopics[ syLastIndex ];
        offset = -1;
    }

    /* if the topic is '>' we are interested in the one after 'LastTopic'  */
    if ( SyStrcmp( topic, ">" ) == 0 ) {
        topic = syLastTopics[ syLastIndex ];
        offset = 1;
    }

    /* if the topic is '<<' we are interested in the first section         */
    last2[0] = '\0';
    if ( SyStrcmp( topic, "<<" ) == 0 ) {
        topic = syLastTopics[ syLastIndex ];
        offset = -2;
    }

    /* if the topic is '>>' we are interested in the next chapter          */
    if ( SyStrcmp( topic, ">>" ) == 0 ) {
        topic = syLastTopics[ syLastIndex ];
        offset = 2;
    }

    /* if the topic is '-' we are interested in the previous section again */
    if ( topic[0] == '-' ) {
        while ( *topic++ == '-' )
            syLastIndex = (syLastIndex + 15) % 16;
        topic = syLastTopics[ syLastIndex ];
        if ( topic[0] == '\0' ) {
            syEchos( "Help: this section has no previous section\n", fin );
            syLastIndex = (syLastIndex + 1) % 16;
            if ( raw )  syStopraw( fin );
            return;
        }
        syLastIndex = (syLastIndex + 15) % 16;
    }

    /* if the topic is '+' we are interested in the last section again     */
    if ( topic[0] == '+' ) {
        while ( *topic++ == '+' )
            syLastIndex = (syLastIndex + 1) % 16;
        topic = syLastTopics[ syLastIndex ];
        if ( topic[0] == '\0' ) {
            syEchos( "Help: this section has no previous section\n", fin );
            syLastIndex = (syLastIndex + 15) % 16;
            if ( raw )  syStopraw( fin );
            return;
        }
        syLastIndex = (syLastIndex + 15) % 16;
    }

    /* if the subject is 'Welcome to GAP' display a welcome message        */
    if ( SyStrcmp( topic, "Welcome to GAP" ) == 0 ) {

        syEchos( "    Welcome to GAP ______________________________", fin );
        syEchos( "_____________ Welcome to GAP\n",                    fin );
        syEchos( "\n",                                                fin );
        syEchos( "    Welcome to GAP.\n",                             fin );
        syEchos( "\n",                                                fin );
        syEchos( "    GAP is a system for computational group theor", fin );
        syEchos( "y.\n",                                              fin );
        syEchos( "\n",                                                fin );
        syEchos( "    Enter '?About GAP'    for a step by step intr", fin );
        syEchos( "oduction to GAP.\n",                                fin );
        syEchos( "    Enter '?Help'         for information how to ", fin );
        syEchos( "use the GAP help system.\n",                        fin );
        syEchos( "    Enter '?Chapters'     for a list of the chapt", fin );
        syEchos( "ers of the GAP help system.\n",                     fin );
        syEchos( "    Enter '?Copyright'    for the terms under whi", fin );
        syEchos( "ch you can use and copy GAP.\n",                    fin );
        syEchos( "\n",                                                fin );
        syEchos( "    In each case do *not* enter the single quotes", fin );
        syEchos( "(') , they are  used in help\n",                    fin );
        syEchos( "    sections only to delimit text that you actual", fin );
        syEchos( "ly enter.\n",                                       fin );
        syEchos( "\n",                                                fin );

        /* remember this topic for the next time                           */
        p = "Welcome to GAP";
        syLastIndex = (syLastIndex + 1) % 16;
        q = syLastTopics[ syLastIndex ];
        while ( *p != '\0' )  *q++ = *p++;
        *q = '\0';

        if ( raw )  syStopraw( fin );
        return;

    }

    /* if the topic is 'chapter' display the table of chapters             */
    if ( SyStrcmp(topic,"chapters")==0 || SyStrcmp(topic,"Chapters")==0 ) {

        /* open the table of contents file                                 */
        filename[0] = '\0';
        SyStrncat( filename, SyHelpname, sizeof(filename)-12 );
        SyStrncat( filename, "manual.toc", 11 );
        fid = SyFopen( filename, "r" );
        if ( fid == -1 ) {
            syEchos( "Help: cannot open the table of contents file '",fin );
            syEchos( filename, fin );
            syEchos( "'\n", fin );
            syEchos( "maybe use the option '-h <hlpname>'?\n", fin );
            if ( raw )  syStopraw( fin );
            return;
        }

        /* print the header line                                           */
        syEchos( "    Table of Chapters _________________", fin );
        syEchos( "____________________ Table of Contents\n", fin );

        /* scan the table of contents for chapter lines                    */
        offset = 2;
        while ( SyFgets( line, sizeof(line), fid ) ) {

            /* parse table of contents line                                */
            for ( p = line; *p != '\0' && ! IsDigit(*p); p++ )  ;
            for ( i = 0; IsDigit(*p); p++ )  i = 10*i+*p-'0';
            if ( *p == '.' )  p++;
            for ( j = 0; IsDigit(*p); p++ )  j = 10*j+*p-'0';
            if ( *p == '}' )  p++;
            if ( i == 0 || ! IsAlpha(*p) ) {
              syEchos("Help: contentsline is garbage in 'manual.toc'",fin);
              SyFclose( fid );
              if ( raw )  syStopraw( fin );
              return;
            }

            /* skip nonchapter lines                                       */
            if ( j != 0 )  continue;

            /* stop every 24 lines                                         */
            if ( offset == SyNrRows && raw ) {
              syEchos( "    -- <space> for more --", fin );
              ch = syGetch( fin );
              syEchos("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b",
                      fin);
              syEchos( "                          ", fin );
              syEchos("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b",
                      fin);
              if ( ch == 'q' )  {
                  syEchos( "\n", fin );
                  break;
              }
              else if ( ch == '\n' || ch == '\r' ) {
                  offset = SyNrRows - 1;
              }
              else {
                  offset = 2;
              }
            }

            /* display the line                                            */
            q = line;
            while ( *p != '}' )  *q++ = *p++;
            *q++ = '\n';
            *q = '\0';
            syEchos( "    ", fin );
            syEchos( line, fin );
            offset++;

        }

        /* remember this topic for the next time                           */
        p = "Chapters";
        syLastIndex = (syLastIndex + 1) % 16;
        q = syLastTopics[ syLastIndex ];
        while ( *p != '\0' )  *q++ = *p++;
        *q = '\0';

        SyFclose( fid );
        if ( raw )  syStopraw( fin );
        return;
    }

    /* if the topic is 'sections' display the table of sections            */
    if ( SyStrcmp(topic,"sections")==0 || SyStrcmp(topic,"Sections")==0 ) {

        /* open the table of contents file                                 */
        filename[0] = '\0';
        SyStrncat( filename, SyHelpname, sizeof(filename)-12 );
        SyStrncat( filename, "manual.toc", 11 );
        fid = SyFopen( filename, "r" );
        if ( fid == -1 ) {
            syEchos( "Help: cannot open the table of contents file '",fin);
            syEchos( filename, fin );
            syEchos( "'\n", fin );
            syEchos( "maybe use the option '-h <hlpname>'?\n", fin );
            if ( raw )  syStopraw( fin );
            return;
        }

        /* print the header line                                           */
        syEchos( "    Table of Sections _________________", fin );
        syEchos( "____________________ Table of Contents\n", fin );

        /* scan the table of contents for chapter lines                    */
        offset = 2;
        while ( SyFgets( line, sizeof(line), fid ) ) {

            /* parse table of contents line                                */
            for ( p = line; *p != '\0' && ! IsDigit(*p); p++ )  ;
            for ( i = 0; IsDigit(*p); p++ )  i = 10*i+*p-'0';
            if ( *p == '.' )  p++;
            for ( j = 0; IsDigit(*p); p++ )  j = 10*j+*p-'0';
            if ( *p == '}' )  p++;
            if ( i == 0 || ! IsAlpha(*p) ) {
              syEchos("Help: contentsline is garbage in 'manual.toc'",fin);
              SyFclose( fid );
              if ( raw )  syStopraw( fin );
              return;
            }

            /* stop every 24 lines                                         */
            if ( offset == SyNrRows && raw ) {
              syEchos( "    -- <space> for more --", fin );
              ch = syGetch( fin );
              syEchos("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b",
                      fin);
              syEchos( "                          ", fin );
              syEchos("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b",
                      fin);
              if ( ch == 'q' )  {
                  syEchos( "\n", fin );
                  break;
              }
              else if ( ch == '\n' || ch == '\r' ) {
                  offset = SyNrRows - 1;
              }
              else {
                  offset = 2;
              }
            }

            /* display the line                                            */
            q = line;
            while ( *p != '}' )  *q++ = *p++;
            *q++ = '\n';
            *q = '\0';
            if ( j == 0 )  syEchos( "    ", fin );
            else            syEchos( "        ", fin );
            syEchos( line, fin );
            offset++;

        }

        /* remember this topic for the next time                           */
        p = "Sections";
        syLastIndex = (syLastIndex + 1) % 16;
        q = syLastTopics[ syLastIndex ];
        while ( *p != '\0' )  *q++ = *p++;
        *q = '\0';

        SyFclose( fid );
        if ( raw )  syStopraw( fin );
        return;
    }

    /* if the topic is 'Copyright' print the copyright                     */
    if ( SyStrcmp(topic,"copyright")==0 || SyStrcmp(topic,"Copyright")==0 ) {

        /* open the copyright file                                         */
        filename[0] = '\0';
        SyStrncat( filename, SyHelpname, sizeof(filename)-14 );
        SyStrncat( filename, "copyrigh.tex", 13 );
        fid = SyFopen( filename, "r" );
        if ( fid == -1 ) {
            syEchos( "Help: cannot open the copyright file '",fin);
            syEchos( filename, fin );
            syEchos( "'\n", fin );
            syEchos( "maybe use the option '-h <helpname>'?\n", fin );
            if ( raw )  syStopraw( fin );
            return;
        }

        /* print the header line                                           */
        syEchos( "    Copyright _________________________", fin );
        syEchos( "____________________________ Copyright\n", fin );

        /* print the contents of the file                                  */
        offset = 2;
        while ( SyFgets( line, sizeof(line), fid ) ) {

            /* skip lines that begin with a '%'                            */
            if ( line[0] == '%' )  continue;

            /* skip the line that begins with '\thispagestyle'             */
            p = line;
            q = "\\thispagestyle";
            while ( *p == *q ) { p++; q++; }
            if ( *q == '\0' )  continue;

            /* stop every 24 lines                                         */
            if ( offset == SyNrRows && raw ) {
              syEchos( "    -- <space> for more --", fin );
              ch = syGetch( fin );
              syEchos("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b",
                      fin);
              syEchos( "                          ", fin );
              syEchos("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b",
                      fin);
              if ( ch == 'q' )  {
                  syEchos( "\n", fin );
                  break;
              }
              else if ( ch == '\n' || ch == '\r' ) {
                  offset = SyNrRows - 1;
              }
              else {
                  offset = 2;
              }
            }

            /* fixup the copyright line                                    */
            p = line;
            q = "{\\large";
            while ( *p == *q ) { p++; q++; }
            if ( *q == '\0' ) {
                syEchos( "    Copyright (c) 1992 ", fin );
                syEchos( "by Lehrstuhl D fuer Mathematik\n", fin );
                continue;
            }

            /* display the line                                            */
            p = line;
            q = last;
            spaces = 0;
            while ( *p != '\0' ) {
                if ( *p == '\\' || *p == '{' || *p == '}' ) {
                    if ( last < q && q[-1] == ' ' )
                        *q++ = ' ';
                    else
                        spaces++;
                }
                else if ( *p == ' ' ) {
                    *q++ = ' ';
                    while ( 0 < spaces ) {
                        *q++ = ' ';
                        spaces--;
                    }
                }
                else {
                    *q++ = *p;
                }
                p++;
            }
            *q = '\0';
            syEchos( "    ", fin );  syEchos( last, fin );
            offset++;
        }

        /* remember this topic for the next time                           */
        p = "Copyright";
        syLastIndex = (syLastIndex + 1) % 16;
        q = syLastTopics[ syLastIndex ];
        while ( *p != '\0' )  *q++ = *p++;
        *q = '\0';

        SyFclose( fid );
        if ( raw )  syStopraw( fin );
        return;
    }

    /* if the topic is '?<string>' search the index                        */
    if ( topic[0] == '?' ) {

        /* skip leading blanks in the topic                                */
        topic++;
        while ( *topic == ' ' )  topic++;

        /* open the index                                                  */
        filename[0] = '\0';
        SyStrncat( filename, SyHelpname, sizeof(filename)-12 );
        SyStrncat( filename, "manual.idx", 11 );
        fid = SyFopen( filename, "r" );
        if ( fid == -1 ) {
            syEchos( "Help: cannot open the index file '", fin);
            syEchos( filename, fin );
            syEchos( "'\n", fin );
            syEchos( "maybe use the option '-h <hlpname>'?\n", fin );
            if ( raw )  syStopraw( fin );
            return;
        }

        /* make a header line                                              */
        line[0] = '\0';
        SyStrncat( line, topic, 40 );
        SyStrncat( line,
        " _________________________________________________________________",
                  73 - 5 );
        line[72-5] = ' ';
        line[73-5] = '\0';
        SyStrncat( line, "Index", 6 );
        SyStrncat( line, "\n", 2 );
        syEchos( "    ", fin );
        syEchos( line, fin );

        /* scan the index                                                  */
        offset = 2;
        while ( SyFgets( line, sizeof(line), fid ) ) {

            /* a '%' line tells us that the next entry is a section name   */
            if ( line[0] == '%' ) {
                while ( line[0] == '%' ) {
                    if ( ! SyFgets( line, sizeof(line), fid ) ) {
                        syEchos( "Help: index file is garbage\n", fin );
                        SyFclose( fid );
                        if ( raw )  syStopraw( fin );
                        return;
                    }
                }
                q = secname;
                p = line + 12;
                while ( *p != '}' )  *q++ = *p++;
                *q = '\0';
            }

            /* skip this entry if we alread had an entry for this section  */
            if ( secname[0] == '\0' )  continue;

            /* try to match topic against this index entry                 */
            for ( r = line + 12; *r != '\0'; r++ ) {
                p = topic;
                q = r;
                while ( (*p | 0x20) == (*q | 0x20) ) { p++; q++; }
                if ( *p == '\0' )  break;
            }
            if ( *r == '\0' )  continue;

            /* stop every 24 lines                                         */
            if ( offset == SyNrRows && raw ) {
              syEchos( "    -- <space> for more --", fin );
              ch = syGetch( fin );
              syEchos("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b",
                      fin);
              syEchos( "                          ", fin );
              syEchos("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b",
                      fin);
              if ( ch == 'q' )  {
                  syEchos( "\n", fin );
                  break;
              }
              else if ( ch == '\n' || ch == '\r' ) {
                  offset = SyNrRows - 1;
              }
              else {
                  offset = 2;
              }
            }

            /* print the index line                                        */
            syEchos( "    ", fin );
            syEchos( secname, fin );
            p = secname;
            q = line + 12;
            while ( *p == *q ) { p++; q++; }
            if ( *p != '\0' ) {
                syEchos( " (", fin );
                for ( p = line + 12; *p != '}'; p++ ) ;
                *p = '\0';
                syEchos( line + 12, fin );
                syEchos( ")", fin );
            }
            syEchos( "\n", fin );
            offset++;

            /* we dont want no more index entries for this section         */
            secname[0] = '\0';

        }

        /* close the index again and return                                */
        SyFclose( fid );
        if ( raw )  syStopraw( fin );
        return;

    }

    /* open the table of contents                                          */
    filename[0] = '\0';
    SyStrncat( filename, SyHelpname, sizeof(filename)-12 );
    SyStrncat( filename, "manual.toc", 11 );
    fid = SyFopen( filename, "r" );
    if ( fid == -1 ) {
        syEchos( "Help: cannot open the table of contents file '", fin );
        syEchos( filename, fin );
        syEchos( "'\n", fin );
        syEchos( "maybe use the option '-h <hlpname>'?\n", fin );
        if ( raw )  syStopraw( fin );
        return;
    }

    /* search the table of contents                                        */
    chapnr = 0;
    secnr = 0;
    secname[0] = '\0';
    matches = 0;
    while ( SyFgets( line, sizeof(line), fid ) ) {

        /* parse table of contents line                                    */
        for ( p = line; *p != '\0' && ! IsDigit(*p); p++ )  ;
        for ( i = 0; IsDigit(*p); p++ )  i = 10*i+*p-'0';
        if ( *p == '.' )  p++;
        for ( j = 0; IsDigit(*p); p++ )  j = 10*j+*p-'0';
        if ( *p == '}' )  p++;
        if ( i == 0 || ! IsAlpha(*p) ) {
          syEchos("Help: contentsline is garbage in 'manual.toc'",fin);
          SyFclose( fid );
          return;
        }

        /* compare the line with the topic                                 */
        q = topic;
        match = 2;
        while ( *p != '}' && match ) {
            if ( *q != '\0' && (*p | 0x20) == (*q | 0x20) ) {
                p++; q++;
            }
            else if ( *q == ' ' || *q == '\0' ) {
                p++;
                match = 1;
            }
            else {
                match = 0;
            }
        }
        if ( *q != '\0' )  match = 0;

        /* if the offset is '-1' we are interested in the previous section */
        if ( match == 2 && offset == -1 ) {
            if ( last[0] == '\0' ) {
                syEchos("Help: the last section is the first one\n", fin );
                SyFclose( fid );
                if ( raw )  syStopraw( fin );
                return;
            }
            q = line;
            p = last;
            while ( *p != '\0' )  *q++ = *p++;
            *q = '\0';
        }

        /* if the offset is '1' we are interested in the next section      */
        if ( match == 2 && offset == 1 ) {
            if ( ! SyFgets( line, sizeof(line), fid ) ) {
                syEchos("Help: the last section is the last one\n", fin );
                SyFclose( fid );
                if ( raw )  syStopraw( fin );
                return;
            }
        }

        /* if the offset if '-2' we are interested in the first section    */
        if ( match == 2 && offset == -2 ) {
            if ( last2[0] == '\0' ) {
                syEchos("Help: the last section is the first one\n", fin );
                SyFclose( fid );
                if ( raw )  syStopraw( fin );
                return;
            }
            q = line;
            p = last2;
            while ( *p != '\0' )  *q++ = *p++;
            *q = '\0';
        }

        /* if the offset is '2' we are interested in the next chapter      */
        if ( match == 2 && offset == 2 ) {
            while ( 1 ) {
                if ( ! SyFgets( line, sizeof(line), fid ) ) {
                  syEchos("Help: the last section is in the last chapter\n",
                          fin );
                  SyFclose( fid );
                  if ( raw )  syStopraw( fin );
                  return;
                }
                for ( p = line; *p != '\0' && ! IsDigit(*p); p++ )  ;
                for ( ; *p != '}' && *p != '.'; p++ )  ;
                if ( *p == '}' )  break;
            }
        }

        /* parse table of contents line (again)                            */
        for ( p = line; *p != '\0' && ! IsDigit(*p); p++ )  ;
        for ( i = 0; IsDigit(*p); p++ )  i = 10*i+*p-'0';
        if ( *p == '.' )  p++;
        for ( j = 0; IsDigit(*p); p++ )  j = 10*j+*p-'0';
        if ( *p == '}' )  p++;
        if ( i == 0 || ! IsAlpha(*p) ) {
          syEchos("Help: contentsline is garbage in 'manual.toc'",fin);
          SyFclose( fid );
          if ( raw )  syStopraw( fin );
          return;
        }

        /* if this is a precise match remember chapter and section number  */
        if ( match == 2 ) {

            /* remember the chapter and section number                     */
            chapnr = i;
            secnr  = j;

            /* get the section name                                        */
            q = secname;
            while ( *p != '}' )  *q++ = *p++;
            *q = '\0';

            /* we dont have to look further                                */
            matches = 1;
            break;
        }

        /* append a weak match to the list of matches                      */
        else if ( match == 1 ) {

            /* remember the chapter and section number                     */
            chapnr = i;
            secnr  = j;

            /* append the section name to the list of sections             */
            q = secname;
            while ( *q != '\0' )  q++;
            if ( q != secname && q < secname+sizeof(secname)-1 )
                *q++ = '\n';
            while ( *p != '}' && q < secname+sizeof(secname)-1 )
                *q++ = *p++;
            *q = '\0';

            /* we have to continue the search                              */
            matches++;
        }

        /* copy this line into <last>                                      */
        q = last;
        p = line;
        while ( *p != '\0' ) *q++ = *p++;
        *q = '\0';

        /* if the line is a chapter line copy it into <last2>              */
        if ( j == 0 ) {
            q = last2;
            p = line;
            while ( *p != '\0' )  *q++ = *p++;
            *q = '\0';
        }

    }

    /* close the table of contents file                                    */
    SyFclose( fid );

    /* if no section was found complain                                    */
    if ( matches == 0 ) {
        syEchos( "Help: no section with this name was found\n", fin );
        if ( raw )  syStopraw( fin );
        return;
    }

    /* if several sections were found return                               */
    if ( 2 <= matches ) {
        syEchos( "Help: several sections match this topic\n", fin );
        syEchos( secname, fin );
        syEchos( "\n", fin );
        if ( raw )  syStopraw( fin );
        return;
    }

    /* if this is the first time we help collect the chapter file names    */
    if ( syChapnames[0][0] == '\0' ) {

        /* open the 'manual.tex' file                                      */
        filename[0] = '\0';
        SyStrncat( filename, SyHelpname, sizeof(filename)-12 );
        SyStrncat( filename, "manual.tex", 11 );
        fid = SyFopen( filename, "r" );
        if ( fid == -1 ) {
            syEchos( "Help: cannot open the manual file '", fin );
            syEchos( filename, fin );
            syEchos( "'\n", fin );
            syEchos( "maybe use the option '-h <hlpname>'?\n", fin );
            if ( raw )  syStopraw( fin );
            return;
        }

        /* scan this file for '\Include' lines, each contains one chapter  */
        offset = 0;
        while ( SyFgets( line, sizeof(line), fid ) ) {
            p = line;
            q = "\\Include{";
            while ( *p == *q ) { p++; q++; }
            if ( *q == '\0' ) {
                q = syChapnames[offset];
                while ( *p != '}' )  *q++ = *p++;
                *q = '\0';
                offset++;
            }
        }

        /* close the 'manual.tex' file again                               */
        SyFclose( fid );

    }

    /* try to open the chapter file                                        */
    filename[0] = '\0';
    SyStrncat( filename, SyHelpname, sizeof(filename)-13 );
    SyStrncat( filename, syChapnames[chapnr-1], 9 );
    SyStrncat( filename, ".tex", 4 );
    fid = SyFopen( filename, "r" );
    if ( fid == -1 ) {
        syEchos( "Help: cannot open the chapter file '", fin );
        syEchos( filename, fin );
        syEchos( "'\n", fin );
        syEchos( "maybe use the option '-h <hlpname>'?\n", fin );
        if ( raw )  syStopraw( fin );
        return;
    }

    /* create the line we are looking for                                  */
    if ( secnr == 0 ) {
        secline[0] = '\0';
        SyStrncat( secline, "\\Chapter{", 10 );
        SyStrncat( secline, secname, sizeof(secline)-10 );
    }
    else {
        secline[0] = '\0';
        SyStrncat( secline, "\\Section{", 10 );
        SyStrncat( secline, secname, sizeof(secline)-10 );
    }

    /* search the file for the correct '\Chapter' or '\Section' line       */
    match = 0;
    while ( ! match && SyFgets( line, sizeof(line), fid ) ) {
        p = line;
        q = secline;
        while ( *p == *q ) { p++; q++; }
        match = (*q == '\0' && *p == '}');
        p = line;
        q = "\\Chapter{";
        while ( *p == *q ) { p++; q++; }
        if ( *q == '\0' ) {
            q = chapname;
            while ( *p != '}' )  *q++ = *p++;
            *q = '\0';
        }
    }

    /* raise an error if this line was not found                           */
    if ( ! match ) {
        syEchos( "Help: could not find section '", fin );
        syEchos( secname, fin );
        syEchos( "' in chapter file '", fin );
        syEchos( filename, fin );
        syEchos( "'\n", fin );
        SyFclose( fid );
        if ( raw )  syStopraw( fin );
        return;
    }

    /* remember this topic for the next time                               */
    p = secname;
    syLastIndex = (syLastIndex + 1) % 16;
    q = syLastTopics[ syLastIndex ];
    while ( *p != '\0' )  *q++ = *p++;
    *q = '\0';

    /* make a header line                                                  */
    line[0] = '\0';
    SyStrncat( line, secname, 40 );
    SyStrncat( line,
    " _____________________________________________________________________",
             73 - SyStrlen(chapname) );
    line[72-SyStrlen(chapname)] = ' ';
    line[73-SyStrlen(chapname)] = '\0';
    SyStrncat( line, chapname, SyStrlen(chapname)+1 );
    SyStrncat( line, "\n", 2 );
    syEchos( "    ", fin );
    syEchos( line, fin );

    /* print everything from here to the next section line                 */
    offset = 2;
    status = 'a';
    while ( SyFgets( line, sizeof(line), fid ) ) {

        /* skip lines that begin with '\index{'                            */
        p = line;
        q = "\\index{";
        while ( *p == *q ) { p++; q++; }
        if ( *q == '\0' )  continue;

        /* skip lines that begin with '\newpage'                           */
        p = line;
        q = "\\newpage";
        while ( *p == *q ) { p++; q++; }
        if ( *q == '\0' )  continue;

        /* skip lines that begin with '\begin{'                            */
        p = line;
        q = "\\begin{";
        while ( *p == *q ) { p++; q++; }
        if ( *q == '\0' )  continue;

        /* skip lines that begin with '\end{'                              */
        p = line;
        q = "\\end{";
        while ( *p == *q ) { p++; q++; }
        if ( *q == '\0' )  continue;

        /* break if we reach a '%%%%%%%%%%%%%%%...' line                   */
        p = line;
        q = "%%%%%%%%%%%%%%%%";
        while ( *p == *q ) { p++; q++; }
        if ( *q == '\0' )  break;

        /* skip other lines that begin with a '%'                          */
        p = line;
        q = "%";
        while ( *p == *q ) { p++; q++; }
        if ( *q == '\0' )  continue;

        /* stop every 24 lines                                             */
        if ( offset == SyNrRows && raw ) {
            syEchos( "    -- <space> for more --", fin );
            ch = syGetch( fin );
            syEchos("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b",
                    fin);
            syEchos( "                          ", fin );
            syEchos("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b",
                    fin);
            if ( ch == 'q' )  {
                syEchos( "\n", fin );
                break;
            }
            else if ( ch == '\n' || ch == '\r' ) {
                offset = SyNrRows - 1;
            }
            else {
                offset = 2;
            }
        }

        /* insert empty line for '\vspace{'                                */
        p = line;
        q = "\\vspace{";
        while ( *p == *q ) { p++; q++; }
        if ( *q == '\0' ) {
            syEchos( "\n", fin );
            offset++;
            continue;
        }

        /* display the line                                                */
        p = line;
        q = last;
        spaces = 0;
        while ( *p != '\0' ) {
            if ( *p == '\\' && status != '|' ) {
                if ( last < q && q[-1] == ' ' )
                    *q++ = ' ';
                else
                    spaces++;
            }
            else if ( *p=='{' && (line==p || p[-1]!='\\') && status!='|' ) {
                if ( status == '$' )
                    *q++ = '(';
                else if ( last < q && q[-1] == ' ' )
                    *q++ = ' ';
                else
                    spaces++;
            }
            else if ( *p=='}' && (line==p || p[-1]!='\\') && status!='|' ) {
                if ( status == '$' )
                    *q++ = ')';
                else if ( last < q && q[-1] == ' ' )
                    *q++ = ' ';
                else
                    spaces++;
            }
            else if ( *p=='$' && (line==p || p[-1]!='\\') && status!='|' ) {
                if ( last < q && q[-1] == ' ' )
                    *q++ = ' ';
                else
                    spaces++;
                if ( status != '$' )
                    status = '$';
                else
                    status = 'a';
            }
            else if ( *p == ' ' && status != '|' ) {
                *q++ = ' ';
                while ( 0 < spaces ) {
                    *q++ = ' ';
                    spaces--;
                }
            }
            else if ( *p=='|' && (line==p || p[-1]!='\\'
                                  || status=='|' || status=='#') ) {
                if ( status == '|' || status == '#' )
                    status = 'a';
                else
                    status = '|';
                spaces++;
            }
            else if ( *p == '#' ) {
                if ( status == '|' )
                    status = '#';
                *q++ = *p;
            }
            else if ( *p == '\n' ) {
                if ( status == '#' )
                    status = '|';
                *q++ = *p;
            }
            else if ( *p == '>' && line!=p && p[-1]=='\\' ) {
                spaces++;
            }
            else if ( *p == '=' && line!=p && p[-1]=='\\' ) {
                spaces++;
            }
            else {
                *q++ = *p;
            }
            p++;
        }
        *q = '\0';
        syEchos( "    ", fin );  syEchos( last, fin );
        offset++;

    }

    /* close the file again                                                */
    SyFclose( fid );
    if ( raw )  syStopraw( fin );
}


/****************************************************************************
**
*F  SyGetmen( <size> )  . . . . . . . . allocate memory block of <size> bytes
**
**  'SyGetmem' gets  a block of  <size>  bytes from the  operating system and
**  returns a pointer  to it.  <size> must  be a multiple  of 4 and the block
**  returned by 'SyGetmem' is lonword aligned.  It is cleared to contain only
**  zeroes.  If  there  is not enough  memory  available returns '(char*)-1'.
**  'SyGetmem' returns adjacent  blocks on subsequent calls, otherwise Gasman
**  would get confused.
**
**  If the operating system does not support dynamic memory managment, simply
**  give 'SyGetmem' a static buffer, from where it returns the blocks.
*/


/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
**
**  For UNIX,  OS/2, MS-DOS, TOS, and  VMS, 'SyGetmem' calls 'sbrk', checking
**  that the  new block is adjacent to   the old, otherwise  other functions,
**  e.g., 'malloc'  have  called  'sbrk'.   This  can    be dealt   with   by
**  pre'malloc'ing storage with the '-a' option.
*/
#if SYS_BSD||SYS_USG||SYS_OS2_EMX||SYS_MSDOS_DJGPP||SYS_TOS_GCC2||SYS_VMS

#ifndef SYS_HAS_MISC_PROTO              /* UNIX decl. from 'man'           */
extern  char *          sbrk P(( int ));
#endif

char *          syHighmem;

char *          SyGetmem ( size )
    long                size;
{
    char *              ret;

    /* force alignment on first call                                       */
    if ( syHighmem == (char*)0 )
        ret = sbrk( 4 - (int)sbrk(0) % 4 );

    /* get the memory                                                      */
    ret = sbrk( (int)size );

    /* check that the new memory is adjacent to the last block             */
    if ( ret != (char*)-1 && syHighmem != 0 && ret != syHighmem ) {
        fputs("gap: sorry, cannot extend the workspace, ",stderr);
        fputs("maybe use option '-a <memory>'?\n",stderr);
        SyExit( 1 );
    }

    /* remember the high memory for the next call                          */
    syHighmem = ret + size;

    /* return address of the block                                         */
    return ret;
}

#endif


/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
**
**  Under MACH virtual memory managment functions are used instead of 'sbrk'.
*/
#if SYS_MACH

#ifdef ARCH_INCLUDE
# include       <mach/mach.h>           /* mach 3.0 memory functions       */
#else
# include       <mach.h>                /* mach 2.0 memory functions       */
#endif

vm_address_t      syBase  = 0;
long              sySize  = 0;
long              syUsed  = 0;

/* 'SyGetmem' uses virtual memory on a NeXT                                */
char *          SyGetmem ( size )
    long                size;
{
    vm_address_t        adr;
    long                new;

    /* allocate memory anywhere on first call                              */
    if ( syBase == 0 ) {
        sySize = ( (size+vm_page_size-1) / vm_page_size ) * vm_page_size;
        syUsed = size;
        if ( vm_allocate(task_self(),&syBase,sySize,TRUE) != KERN_SUCCESS ) {
            fputs("gap: panic 'SyGetmem' vm_allocate failed!\n",stderr);
            SyExit(1);
        }
        return (char*) syBase;
    }

    /* if the new request still fits return                                */
    else if ( syUsed + size <= sySize ) {
        syUsed += size;
        return (char*) syBase + (syUsed-size);
    }

    /* get more memory from system                                         */
    else {
        new = ( (size+vm_page_size-1) / vm_page_size ) * vm_page_size;
        adr = (vm_address_t)( (char*) syBase + sySize );
        if ( vm_allocate(task_self(),&adr,new,FALSE) != KERN_SUCCESS ) {
            fputs("gap: sorry, cannot extend the workspace, ",stderr);
            fputs("maybe use option '-a <memory>'?\n",stderr);
            SyExit( 1 );
        }
        syUsed += size;
        sySize += new;
        return (char*) syBase + (syUsed-size);
    }
}

#endif


/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
**
**  For the MAC under MPW we currently use 'calloc'.  This  does not allow to
**  extend the arena, but this is a problem of the memory manager anyhow.
*/
#if SYS_MAC_MPW

#ifndef SYS_HAS_CALLOC_PROTO
extern  char *          calloc P(( int, int ));
#endif

char *          syWorkspace;

char *          SyGetmem ( size )
    long                size;
{
    /* get the memory                                                      */
    /*N 1993/05/29 martin try to make it possible to extend the arena      */
    if ( syWorkspace == 0 ) {
        syWorkspace = calloc( (int)size/4, 4 );
        syWorkspace = (char*)(((long)syWorkspace + 3) & ~3);
        return syWorkspace;
    }
    else {
        return (char*)-1;
    }
}

#endif


/** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
**
**  For Mac under Think C we use 'NewPtr'.  This does not allow to extend the
**  area, but this is a problem of the memory manager anyhow.
*/
#if SYS_MAC_SYC

#ifndef SYS_STRING_H                    /* string functions:               */
# include      <string.h>               /* 'memset'                        */
# define SYS_STRING_H
#endif
#ifndef SYS_HAS_MEMSET_PROTO            /* ANSI/TRAD decl. from H&S ?.?    */
extern  void *          memset P(( void * mem, int chr, size_t size ));
#endif

char *          syWorkspace;

char *          SyGetmem ( size )
    long                size;
{
    /* get the memory                                                      */
    if ( syWorkspace == 0 ) {
        syWorkspace = (char*)NewPtr( size + 3 );
        syWorkspace = (char*)(((long)syWorkspace + 3) & ~3);
        memset( syWorkspace, 0, size );
        return syWorkspace;
    }
    else {
        return (char*)-1;
    }
}
#endif


/****************************************************************************
**
*F  InitSystem( <argc>, <argv> )  . . . . . . . . . initialize system package
**
**  'InitSystem' is called very early during the initialization from  'main'.
**  It is passed the command line array  <argc>, <argv>  to look for options.
**
**  For UNIX it initializes the default files 'stdin', 'stdout' and 'stderr',
**  installs the handler 'syAnsIntr' to answer the user interrupts '<ctr>-C',
**  scans the command line for options, tries to  find  'LIBNAME/init.g'  and
**  '$HOME/.gaprc' and copies the remaining arguments into 'SyInitfiles'.
*/
#ifndef SYS_STDLIB_H                    /* ANSI standard functions         */
# if SYS_ANSI
#  include      <stdlib.h>
# endif
# define SYS_STDLIB_H
#endif
#ifndef SYS_HAS_MISC_PROTO              /* ANSI/TRAD decl. from H&S 20, 13 */
extern  char *          getenv P(( SYS_CONST char * ));
extern  int             atoi P(( SYS_CONST char * ));
#endif
#ifndef SYS_HAS_MISC_PROTO              /* UNIX decl. from 'man'           */
extern  int             isatty P(( int ));
extern  char *          ttyname P(( int ));
#endif

#ifndef SYS_STDLIB_H                    /* ANSI standard functions         */
# if SYS_ANSI
#  include      <stdlib.h>
# endif
# define SYS_STDLIB_H
#endif
#ifndef SYS_HAS_MALLOC_PROTO
# if SYS_ANSI                           /* ANSI decl. from H&S 16.1, 16.2  */
extern  void *          malloc P(( size_t ));
extern  void            free P(( void * ));
# else                                  /* TRAD decl. from H&S 16.1, 16.2  */
extern  char *          malloc P(( unsigned ));
extern  void            free P(( char * ));
# endif
#endif

#if SYS_TOS_GCC2
# ifndef SYS_BASEPAGE_H                 /* definition of basepage          */
#  include      <basepage.h>
#  define SYS_BASEPAGE_H
# endif
#endif

#if SYS_MAC_SYC
#ifndef SYS_CONSOLE_H                   /* console stuff:                  */
# include       <Console.h>             /* 'console_options', 'cinverse'   */
# define SYS_CONSOLE_H
#endif
#endif

#if SYS_MAC_MPW || SYS_MAC_SYC
# ifndef SYS_HAS_TOOL
#  ifndef SYS_MEMORY_H                  /* Memory stuff:                   */
#   include     <Memory.h>              /* 'GetApplLimit', 'SetApplLimit', */
#   define SYS_MEMORY_H                 /* 'MaxApplZone', 'StackSpace',    */
#  endif                                /* 'MaxMem'                        */
# endif
#endif

#if SYS_MAC_MPW || SYS_MAC_SYC
# ifndef SYS_HAS_TOOL
char *          syArgv [128];
char            syArgl [1024];
# endif
#endif

#if SYS_MAC_SYC
long *          dedgen;
long *          dedcos;
long            dedSize = 40960;
#endif

void            InitSystem ( argc, argv )
    int                 argc;
    char *              argv [];
{
    long                fid;            /* file identifier                 */
    long                pre = 63*1024;  /* amount to pre'malloc'ate        */
    int                 gaprc = 1;      /* read the .gaprc file            */
    char *              ptr;            /* pointer to the pre'malloc'ated  */
    long                i, k;           /* loop variables                  */

#if SYS_MAC_MPW || SYS_MAC_SYC
# ifndef SYS_HAS_TOOL
    /* Increase the amount of stack space available to GAP.                */
    /* Following "Inside Macintosh - Memory" 1992, pages 1-42.             */
    /* For use with MPW 'SIOW.o' *after* changing instruction word         */
    /* at 3F94 from 'A063' (call to '_MaxApplZone') to '4E71' (NOP).       */
    /* 'fix_SIOW.c' is the source for an MPW tool, which does this safely. */
    /* Otherwise bungee-jumping the stack will lead to fatal head injuries.*/
    /*                                              Dave Bayer, 1994/07/14 */
    SetApplLimit( GetApplLimit() - (SyStackSpace - StackSpace() + 1024) );
    MaxApplZone();
    if ( StackSpace() < SyStackSpace ) {
        fputs("gap: cannot get enough stack space.\n",stderr);
        SyExit( 1 );
    }
# endif
#endif

    /* open the standard files                                             */
#if SYS_BSD || SYS_MACH || SYS_USG || SYS_VMS
    syBuf[0].fp = stdin;   setbuf( stdin, syBuf[0].buf );
    if ( isatty( fileno(stdin) ) ) {
        if ( isatty( fileno(stdout) )
          && ! SyStrcmp( ttyname(fileno(stdin)), ttyname(fileno(stdout)) ) )
            syBuf[0].echo = stdout;
        else
            syBuf[0].echo = fopen( ttyname(fileno(stdin)), "w" );
        if ( syBuf[0].echo != (FILE*)0 && syBuf[0].echo != stdout )
            setbuf( syBuf[0].echo, (char*)0 );
    }
    else {
        syBuf[0].echo = stdout;
    }
    syBuf[1].fp = stdout;  setbuf( stdout, (char*)0 );
    if ( isatty( fileno(stderr) ) ) {
        if ( isatty( fileno(stdin) )
          && ! SyStrcmp( ttyname(fileno(stdin)), ttyname(fileno(stderr)) ) )
            syBuf[2].fp = stdin;
        else
            syBuf[2].fp = fopen( ttyname(fileno(stderr)), "r" );
        if ( syBuf[2].fp != (FILE*)0 && syBuf[2].fp != stdin )
            setbuf( syBuf[2].fp, syBuf[2].buf );
        syBuf[2].echo = stderr;
    }
    syBuf[3].fp = stderr;  setbuf( stderr, (char*)0 );
#endif
#if SYS_OS2_EMX
    syBuf[0].fp = stdin;   setbuf( stdin, syBuf[0].buf );
    if ( isatty( fileno(stdin) ) ) {
        if ( isatty( fileno(stdout) ) )
            syBuf[0].echo = stdout;
        else
            syBuf[0].echo = fopen( "CON", "w" );
        if ( syBuf[0].echo != (FILE*)0 && syBuf[0].echo != stdout )
            setbuf( syBuf[0].echo, (char*)0 );
    }
    else {
        syBuf[0].echo = stdout;
    }
    syBuf[1].fp = stdout;  setbuf( stdout, (char*)0 );
    if ( isatty( fileno(stderr) ) ) {
        if ( isatty( fileno(stdin) ) )
            syBuf[2].fp = stdin;
        else
            syBuf[2].fp = fopen( "CON", "r" );
        if ( syBuf[2].fp != (FILE*)0 && syBuf[2].fp != stdin )
            setbuf( syBuf[2].fp, syBuf[2].buf );
        syBuf[2].echo = stderr;
    }
    syBuf[3].fp = stderr;  setbuf( stderr, (char*)0 );
#endif
#if SYS_MSDOS_DJGPP || SYS_TOS_GCC2
    syBuf[0].fp = stdin;   setbuf( stdin, syBuf[0].buf );
    syBuf[1].fp = stdout;  setbuf( stdout, (char*)0 );
    syBuf[3].fp = stderr;  setbuf( stderr, (char*)0 );
    if ( isatty( fileno(stderr) ) )
        syBuf[2].fp = stderr;
#endif
#if SYS_MAC_MPW || SYS_MAC_SYC
    syBuf[0].fp = stdin;
    syBuf[1].fp = stdout;
    syBuf[2].fp = stdin;
    syBuf[3].fp = stderr;
#endif

    /* install the signal handler for '<ctr>-C'                            */
#if SYS_BSD || SYS_MACH || SYS_USG || SYS_OS2_EMX || SYS_VMS
    if ( signal( SIGINT, SIG_IGN ) != SIG_IGN )
        signal( SIGINT, syAnswerIntr );
#endif
#if SYS_OS2_EMX
    /* under OS/2, pressing <ctr>-Break sometimes generates SIGBREAK       */
    signal( SIGBREAK, syAnswerIntr );
#endif
#if SYS_MAC_MPW
# ifdef SYS_HAS_TOOL
    signal( SIGINT, &syAnswerIntr );
# endif
#endif
#if SYS_MAC_SYC
    signal( SIGINT, &syAnswerIntr );
#endif

#if SYS_MAC_MPW || SYS_MAC_SYC
# ifndef SYS_HAS_TOOL
    /* the Macintosh doesn't support command line options, read from file  */
    if ( (fid = SyFopen( "gap.options", "r" )) != -1 ) {
        argc = 0;
        argv = syArgv;
        argv[argc++] = "gap";
        ptr = syArgl;
        while ( SyFgets( ptr, (sizeof(syArgl)-1) - (ptr-syArgl), fid )
          && (ptr-syArgl) < (sizeof(syArgl)-1) ) {
            while ( *ptr != '#' && *ptr != '\0' )
                ptr++;
        }
        ptr = syArgl;
        while ( *ptr==' ' || *ptr=='\t' || *ptr=='\n' )  *ptr++ = '\0';
        while ( *ptr != '\0' ) {
            argv[argc++] = ptr;
            while ( *ptr!=' ' && *ptr!='\t' && *ptr!='\n' && *ptr!='\0' ) {
                if ( *ptr=='\\' )
                    for ( k = 0; ptr[k+1] != '\0'; k++ )
                        ptr[k] = ptr[k+1];
                ptr++;
            }
            while ( *ptr==' ' || *ptr=='\t' || *ptr=='\n' )  *ptr++ = '\0';
        }
        SyFclose( fid );
    }
# endif
#endif

    /* scan the command line for options                                   */
    while ( argc > 1 && argv[1][0] == '-' ) {

        if ( SyStrlen(argv[1]) != 2 ) {
            fputs("gap: sorry, options must not be grouped '",stderr);
            fputs(argv[1],stderr);  fputs("'.\n",stderr);
            goto usage;
        }

        switch ( argv[1][1] ) {

        case 'b': /* '-b', supress the banner                              */
            SyBanner = ! SyBanner;
            break;

        case 'g': /* '-g', Gasman should be verbose                        */
            SyGasman = ! SyGasman;
            break;

        case 'l': /* '-l <libname>', change the value of 'LIBNAME'         */
            if ( argc < 3 ) {
                fputs("gap: option '-l' must have an argument.\n",stderr);
                goto usage;
            }
            SyLibname[0] = '\0';
            SyStrncat( SyLibname, argv[2], sizeof(SyLibname)-2 );
#if SYS_BSD || SYS_MACH || SYS_USG || SYS_OS2_EMX
            if ( SyLibname[SyStrlen(SyLibname)-1] != '/'
              && SyLibname[SyStrlen(SyLibname)-1] != ';' )
                SyStrncat( SyLibname, "/", 1 );
#endif
#if SYS_MSDOS_DJGPP || SYS_TOS_GCC2
            if ( SyLibname[SyStrlen(SyLibname)-1] != '\\'
              && SyLibname[SyStrlen(SyLibname)-1] != ';' )
                SyStrncat( SyLibname, "\\", 1 );
#endif
            ++argv; --argc;
            break;

        case 'h': /* '-h <hlpname>', change the value of 'HLPNAME'         */
            if ( argc < 3 ) {
                fputs("gap: option '-h' must have an argument.\n",stderr);
                goto usage;
            }
            SyHelpname[0] = '\0';
#if SYS_BSD || SYS_MACH || SYS_USG || SYS_OS2_EMX
            SyStrncat( SyHelpname, argv[2], sizeof(SyLibname)-2 );
            if ( SyLibname[SyStrlen(SyHelpname)-1] != '/' )
                SyStrncat( SyHelpname, "/", 1 );
#endif
#if SYS_MSDOS_DJGPP || SYS_TOS_GCC2
            SyStrncat( SyHelpname, argv[2], sizeof(SyLibname)-2 );
            if ( SyLibname[SyStrlen(SyHelpname)-1] != '\\' )
                SyStrncat( SyHelpname, "\\", 1 );
#endif
            ++argv; --argc;
            break;

        case 'm': /* '-m <memory>', change the value of 'SyMemory'         */
            if ( argc < 3 ) {
                fputs("gap: option '-m' must have an argument.\n",stderr);
                goto usage;
            }
            SyMemory = atoi(argv[2]);
            if ( argv[2][SyStrlen(argv[2])-1] == 'k'
              || argv[2][SyStrlen(argv[2])-1] == 'K' )
                SyMemory = SyMemory * 1024;
            if ( argv[2][SyStrlen(argv[2])-1] == 'm'
              || argv[2][SyStrlen(argv[2])-1] == 'M' )
                SyMemory = SyMemory * 1024 * 1024;
            ++argv; --argc;
            break;

        case 'a': /* '-a <memory>', set amount to pre'm*a*lloc'ate         */
            if ( argc < 3 ) {
                fputs("gap: option '-a' must have an argument.\n",stderr);
                goto usage;
            }
            pre = atoi(argv[2]);
            if ( argv[2][SyStrlen(argv[2])-1] == 'k'
              || argv[2][SyStrlen(argv[2])-1] == 'K' )
                pre = pre * 1024;
            if ( argv[2][SyStrlen(argv[2])-1] == 'm'
              || argv[2][SyStrlen(argv[2])-1] == 'M' )
                pre = pre * 1024 * 1024;
            ++argv; --argc;
            break;

        case 'n': /* '-n', disable command line editing                    */
            if ( ! syWindow )  syLineEdit = 0;
            break;

        case 'f': /* '-f', force line editing                              */
            if ( ! syWindow )  syLineEdit = 2;
            break;

        case 'q': /* '-q', GAP should be quiet                             */
            SyQuiet = ! SyQuiet;
            break;

        case 'x': /* '-x', specify the length of a line                    */
            if ( argc < 3 ) {
                fputs("gap: option '-x' must have an argument.\n",stderr);
                goto usage;
            }
            SyNrCols = atoi(argv[2]);
            ++argv; --argc;
            break;

        case 'y': /* '-y', specify the number of lines                     */
            if ( argc < 3 ) {
                fputs("gap: option '-y' must have an argument.\n",stderr);
                goto usage;
            }
            SyNrRows = atoi(argv[2]);
            ++argv; --argc;
            break;

        case 'e': /* '-e', do not quit GAP on '<ctr>-D'                    */
            if ( ! syWindow )  syCTRD = ! syCTRD;
            break;

#if SYS_BSD || SYS_MACH || SYS_USG
        case 'p': /* '-p', start GAP package mode for output               */
            syWindow     = 1;
            syLineEdit   = 1;
            syCTRD       = 1;
            syWinPut( 0, "@p", "" );
            syBuf[2].fp = stdin;  syBuf[2].echo = stdout;
            syBuf[3].fp = stdout;
            break;
#endif

#if SYS_MSDOS_DJGPP || SYS_TOS_GCC2 || SYS_MAC_MPW || SYS_MAC_SYC
        case 'z': /* '-z', specify interrupt check frequency               */
            if ( argc < 3 ) {
                fputs("gap: option '-z' must have an argument.\n",stderr);
                goto usage;
            }
            syIsIntrFreq = atoi(argv[2]);
            ++argv; --argc;
            break;
#endif

#if SYS_MAC_SYC
        case 'Z': /* '-Z', specify background check frequency              */
            if ( argc < 3 ) {
                fputs("gap: option '-Z' must have an argument.\n",stderr);
                goto usage;
            }
            syIsBackFreq = atoi(argv[2]);
            ++argv; --argc;
            break;
#endif

#if SYS_OS2_EMX
        case 'E': /* '-E', running under Emacs under OS/2                  */
            syLineEdit = 2;
            syBuf[2].fp = stdin;
            syBuf[2].echo = stderr;
            break;
#endif

        case 'r': /* don't read the '.gaprc' file                          */
            gaprc = ! gaprc;
            break;

        default: /* default, no such option                                */
            fputs("gap: '",stderr);  fputs(argv[1],stderr);
            fputs("' option is unknown.\n",stderr);
            goto usage;

        }

        ++argv; --argc;

    }

#if SYS_MAC_SYC
    /* set up the console window options                                   */
    console_options.title = "\pGAP 3.4.2";
    console_options.nrows = SyNrRows;
    console_options.ncols = SyNrCols;
    console_options.pause_atexit = 0;
    cinverse( 1, stdin );
#endif

#if SYS_MAC_SYC
    /* allocate 'dedgen' und 'dedcos'                                      */
    dedgen = (long*)NewPtr( dedSize * sizeof(long) );
    dedcos = (long*)NewPtr( dedSize * sizeof(long) );
#endif

    /* premalloc stuff                                                     */
    ptr = malloc( pre );
    if ( ptr != 0 )  free( ptr );

    /* try to find 'LIBNAME/init.g' to read it upon initialization         */
    i = 0;  fid = -1;
    while ( fid == -1 && i <= SyStrlen(SyLibname) ) {
        for ( k = i; SyLibname[k] != '\0' && SyLibname[k] != ';'; k++ )  ;
        SyInitfiles[0][0] = '\0';
        if ( sizeof(SyInitfiles[0]) < k-i+6+1 ) {
            fputs("gap: <libname> is too long\n",stderr);
            goto usage;
        }
        SyStrncat( SyInitfiles[0], SyLibname+i, k-i );
        SyStrncat( SyInitfiles[0], "init.g", 6 );
        if ( (fid = SyFopen( SyInitfiles[0], "r" )) != -1 )
            SyFclose( fid );
        i = k + 1;
    }
    if ( fid != -1 ) {
        i = 1;
    }
    else {
        i = 0;
        SyInitfiles[0][0] = '\0';
        if ( ! SyQuiet ) {
            fputs("gap: hmm, I cannot find '",stderr);
            fputs(SyLibname,stderr);
            fputs("init.g', maybe use option '-l <libname>'?\n",stderr);
        }
    }

    if ( gaprc ) {
#if SYS_BSD || SYS_MACH || SYS_USG
      if ( getenv("HOME") != 0 ) {
          SyInitfiles[i][0] = '\0';
          SyStrncat(SyInitfiles[i],getenv("HOME"),sizeof(SyInitfiles[0])-1);
          SyStrncat( SyInitfiles[i], "/.gaprc",
                  (long)(sizeof(SyInitfiles[0])-1-SyStrlen(SyInitfiles[i])));
          if ( (fid = SyFopen( SyInitfiles[i], "r" )) != -1 ) {
              ++i;
              SyFclose( fid );
          }
          else {
              SyInitfiles[i][0] = '\0';
          }
      }
#endif
#if SYS_OS2_EMX || SYS_MSDOS_DJGPP || SYS_TOS_GCC2
      if ( getenv("HOME") != 0 ) {
          SyInitfiles[i][0] = '\0';
          SyStrncat(SyInitfiles[i],getenv("HOME"),sizeof(SyInitfiles[0])-1);
          SyStrncat( SyInitfiles[i], "/gap.rc",
                  (long)(sizeof(SyInitfiles[0])-1-SyStrlen(SyInitfiles[i])));
          if ( (fid = SyFopen( SyInitfiles[i], "r" )) != -1 ) {
              ++i;
              SyFclose( fid );
          }
          else {
              SyInitfiles[i][0] = '\0';
          }
      }
#endif
#if SYS_VMS
      if ( getenv("GAP_INI") != 0 ) {
        SyStrncat(SyInitfiles[i],getenv("GAP_INI"),sizeof(SyInitfiles[0])-1);
        if ( (fid = SyFopen( SyInitfiles[i], "r" )) != -1 ) {
            ++i;
            SyFclose( fid );
        }
        else {
            SyInitfiles[i][0] = '\0';
        }
      }
#endif
#if SYS_MAC_MPW || SYS_MAC_SYC
      SyInitfiles[i][0] = '\0';
      SyStrncat( SyInitfiles[i], "gap.rc",
              (long)(sizeof(SyInitfiles[0])-1-SyStrlen(SyInitfiles[i])));
      if ( (fid = SyFopen( SyInitfiles[i], "r" )) != -1 ) {
          ++i;
          SyFclose( fid );
      }
      else {
          SyInitfiles[i][0] = '\0';
      }
#endif
    }

    /* use the files from the command line                                 */
    while ( argc > 1 ) {
        if ( i >= sizeof(SyInitfiles)/sizeof(SyInitfiles[0]) ) {
            fputs("gap: sorry, cannot handle so many init files.\n",stderr);
            goto usage;
        }
        SyInitfiles[i][0] = '\0';
        SyStrncat( SyInitfiles[i], argv[1], sizeof(SyInitfiles[0])-1 );
        ++i;
        ++argv;  --argc;
    }

#if SYS_TOS_GCC2
    /* for TOS we compute the amount of allocatable memory                 */
    if ( SyMemory <= 0 ) {
        SyMemory = (long)_base->p_hitpa - (long)_base->p_lowtpa
                   - _base->p_tlen - _base->p_dlen - _base->p_blen
                   - _stksize - pre - 8192 + SyMemory;
    }
#endif

#if SYS_VMS
    /* for VMS we need to create the virtual keyboards for raw reading     */
    smg$create_virtual_keyboard( &syVirKbd );
#endif

#if SYS_MAC_MPW || SYS_MAC_SYC
# ifndef SYS_HAS_TOOL
    /* find out how much memory we can now allocate in the zone            */
    if ( SyMemory <= 0 ) {
        SyMemory = MaxMem( &i ) - SyMemory - 384*1024;
        if ( SyMemory < 1024*1024 ) {
            fputs(
        "gap: please use the 'Get Info' command in the Finder 'Desk' menu\n",
                  stderr );
            fputs(
        "     to set the minimum amount of memory to at least 2560 KByte,\n",
                  stderr );
            fputs(
        "     and the preferred amount of memory to 5632 KByte or more.\n",
                  stderr );
            SyExit( 1 );
        }
    }
# endif
#endif

    /* start the clock                                                     */
    syStartTime = SyTime();

    /* now we start                                                        */
    return;

    /* print a usage message                                               */
 usage:
    fputs("usage: gap [-l <libname>] [-h <hlpname>] [-m <memory>]\n",stderr);
    fputs("           [-g] [-n] [-q] [-b] [-x <nr>]  [-y <nr>]\n",stderr);
    fputs("           <file>...\n",stderr);
    fputs("  run the Groups, Algorithms and Programming system.\n",stderr);
    SyExit( 1 );
}



