Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/GAP/pkg/xgap/src.x11/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 14.8.2025 mit Größe 34 kB image not shown  

Quelle  pty.c   Sprache: C

 
/****************************************************************************
**
*W  pty.c                       XGAP source                      Frank Celler
**
**
*Y  Copyright 1995-1997,  Lehrstuhl D fuer Mathematik,  RWTH Aachen,  Germany
*Y  Copyright 1997,       Frank Celler,                 Huerth,       Germany
**
**  This file contains all the code for handling pseudo ttys.  'GetMasterPty'
**  is based on code from 'xterm'.
**
**  GAP is started in a special mode that will mask special characters.  The
**  following '@' sequences produced by GAP are recoginzed:
**
**    'pX.'           package mode version X
**    '@' a single '@'
**    'A'..'Z' a control character
**    '1','2','3','4','5','6' full garbage collection information
**    '!','"','#','$','%','&'   partial garbage collection information
**    'e'               gap is waiting for error input
**    'c'               completion started
**    'f'               error output
**    'h'               help started
**    'i'               gap is waiting for input
**    'm'              end of 'Exec'
**    'n'               normal output
**    'r'               the current input line follows
**    'sN'              ACK for '@yN'
**    'w'               a window command follows
**    'x'               the current input line is empty
**    'z'  start of 'Exec'
*/

#include    "utils.h"

#include    "gaptext.h"
#include    "xcmds.h"
#include    "xgap.h"

#include    "pty.h"

#ifdef HAVE_OPENPTY
  #if defined(HAVE_UTIL_H)
    #include <util.h>     /* for openpty() on Mac OS X, OpenBSD and NetBSD */
  #elif defined(HAVE_LIBUTIL_H)
    #include <libutil.h>  /* for openpty() on FreeBSD */
  #elif defined(HAVE_PTY_H)
    #include <pty.h>      /* for openpty() on Cygwin, Interix, OSF/1 4 and 5 */
  #endif
#endif


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

*F * * * * * * * * * * * * * * local variables * * * * * * * * * * * * * * *
*/



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

*V  GapPID  . . . . . . . . . . . . . . . . . . . . . . . . gap subprocess id
*/

static int GapPID = -1;


/****************************************************************************
**
*V  FromGap . . . . . . . . . . . . . . . . . . . . . . for messages from gap
*/

static int FromGap;


/****************************************************************************
**
*V  ToGap . . . . . . . . . . . . . . . . . . . . . . . . for messages to gap
*/

static int ToGap;


/* * * * * * * * * * * * * *  global variables * * * * * * * * * * * * * * */


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

*V  QuitGapCtrlD  . . . . . . . . . . . . . . . . . . . . . . . quit on CTR-D
*/

Boolean QuitGapCtrlD = FALSE;


/****************************************************************************
**
*V  ScreenSizeBuffer  . . . . . . . . . . . . . .  screen size change command
*/

char ScreenSizeBuffer[1024] = { 0 };


/****************************************************************************
**
*V  ExecRunning . . . . . . . . . . . . . . . . . .  external program running
*/

Boolean ExecRunning = False;


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

*F * * * * * * * * * * * *  communication with GAP * * * * * * * * * * * * *
*/



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

*F  ReadGap( <line>, <len> )  . . . . . . . . . . . . . . . . read gap output
*/

#ifdef DEBUG_ON

Int READ_GAP (
    String      file,
    Int         where,
    String      line,
    Int         len)
{
    Int         n;
    Int         old;

    if ( Debug & D_COMM )
    {
 printf( "%04d:%s: ReadGap( buf, %d ) = ", where, file, len );
 fflush( stdout );
    }
    if ( len < 0 )
    {
        len = read( FromGap, line, -len );
 if ( Debug & D_COMM )
 {
     if ( len == -1 )
  fprintf( stdout, "-1: no input\n" );
     else
     {
  fprintf( stdout, "%d: '", len );
  fwrite( line, 1, len, stdout );
  fprintf( stdout, "'\n" );
     }
     fflush( stdout );
 }
 return len;
    }
    else
    {
        old = len;
        while ( 0 < len )
        {
            while ( ( n = read( FromGap, line, len ) ) < 0 )
  ;
            line = line + n;
            len  = len - n;
        }
 if ( Debug & D_COMM )
 {
     fprintf( stdout, "%d: '", old );
     fwrite( line-old, 1, old, stdout );
     fprintf( stdout, "'\n" );
     fflush( stdout );
 }
        return old;
    }
}

#else

Int ReadGap (
    String      line,
    Int         len)
{
    Int         n;
    Int         old;

    if ( len < 0 )
        return read( FromGap, line, -len );
    else
    {
        old = len;
        while ( 0 < len )
        {
            while ( ( n = read( FromGap, line, len ) ) < 0 )
  ;
            line = line + n;
            len  = len - n;
        }
        return old;
    }
}

#endif


/****************************************************************************
**
*F  WriteGap( <line>, <len> ) . . . . . . . . . . . . . . . . write gap input
*/

#include <errno.h>

#ifdef DEBUG_ON

void WRITE_GAP (
    String      file,
    Int         where,
    String      line,
    Int         len)
{
    Int         res;

    if ( Debug & D_COMM )
    {
 printf( "%04d:%s: WriteGap( %d ) = '", where, file, len );
 fwrite( line, 1, len, stdout );
 fprintf( stdout, "'\n" );
 fflush( stdout );
    }
    while ( 0 < len )
    {
        res = write( ToGap, line, len );
        if ( res < 0 )
        {
     if ( errno == EAGAIN )
  continue;
            perror( "WriteGap" );
            KillGap();
            exit(1);
        }
        len  -= res;
        line += res;
    }
}

#else

void WriteGap (
    String      line,
    Int         len)
{
    Int         res;

    while ( 0 < len )
    {
        res = write( ToGap, line, len );
        if ( res < 0 )
        {
     if ( errno == EAGAIN )
  continue;
            perror( "WriteGap" );
            KillGap();
            exit(1);
        }
        len  -= res;
        line += res;
    }
}

#endif


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

*V  InBuffer  . . . . . . . . . . . . . . . . . . . . .  buffer of gap output
*/

#define SIZE_BUFFER 16000

static struct _in_buf
{
    char    buffer[SIZE_BUFFER];
    Int     pos;
    Int     len;
}
InBuffer;


/****************************************************************************
**
*V  GapBuffer . . . . . . . . . . . . . . . . temporary buffer for 'ReadLine'
*/

static char GapBuffer[SIZE_BUFFER];


/****************************************************************************
**
*V  LastLine  . . . . . . . . . . . . . . . . . . . .  beginning of last line
*/

static Int LastLine;


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

*D  CURRENT( <buf> )  . . . . . . . . . . . . . . . . . . . .  current symbol
*/

#define CURRENT(buf)     ((buf).buffer[(buf).pos])


/****************************************************************************
**
*D  READ_CURRENT( <buf> ) . . . . . . . . . . . . . .  consume current symbol
*/

#define READ_CURRENT(buf)   ((buf).buffer[(buf).pos++])


/****************************************************************************
**
*D  HAS_INPUT( <buf> )  . . . . . . . . . . . . . . . . . . . check for input
*/

#define HAS_INPUT(buf) ( ((buf).len <= (buf).pos) ? (buf).pos = 0, \
      ((buf).len=ReadGap((buf).buffer,-SIZE_BUFFER))>0 :\
     1 )


/****************************************************************************
**
*D  HAS_BUFFERED( <buf> ) . . . . . . . . . . . . .  check for buffered input
*/

#define HAS_BUFFERED(buf)   ( (buf).pos < (buf).len )


/****************************************************************************
**
*D  LOOK_AHEAD( <buf> ) . . . look ahead if there is enough input, dont check
*/

#define LOOK_AHEAD(buf) ( ((buf).pos+1 < (buf).len ) ? \
     ((buf).buffer)[(buf).pos+1] : '\0' )


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

*F  WaitInput( <buf> )  . . . . . . . . . . . . . . .  wait for one character
*/

void WaitInput (
    struct _in_buf    * buf)
{
    Int                 len;

    if ( buf->len <= buf->pos )
    {
 buf->pos = 0;
 ReadGap( buf->buffer, 1 );
 len = ReadGap( buf->buffer+1, -(SIZE_BUFFER-1) );
 buf->len = (len < 0) ? 1 : len+1;
    }
}


/****************************************************************************
**
*F  WaitInput2( <buf> ) . . . . . . . . . . . . . . . wait for two characters
*/

void WaitInput2 (
    struct _in_buf    * buf)
{
    Int                 len;

    if ( buf->len <= 1 + buf->pos )
    {
 if ( buf->pos+1 == buf->len )
 {
     *buf->buffer = buf->buffer[buf->pos];
     buf->pos = 0;
     ReadGap( buf->buffer+1, 1 );
     len = ReadGap( buf->buffer+2, -(SIZE_BUFFER-2) );
     buf->len = (len < 0) ? 2 : len+2;
 }
 else
 {
     buf->pos = 0;
     ReadGap( buf->buffer, 2 );
     len = ReadGap( buf->buffer+2, -(SIZE_BUFFER-2) );
     buf->len = (len < 0) ? 2 : len+2;
 }
    }
}

/****************************************************************************
**
*F  ReadLine( <buf> ) . . . . . . . . . . . . . . . . . . . . . . read a line
*/

void ReadLine (
    struct _in_buf    * buf)
{
    String              ptr = GapBuffer;

    do
    {
 WaitInput(buf);
 if ( CURRENT(*buf) == '\n' )
 {
     *ptr++ = READ_CURRENT(*buf);
     *ptr   = 0;
     return;
 }
 else if ( CURRENT(*buf) == '\r' )
     (void) READ_CURRENT(*buf);
 else if ( CURRENT(*buf) == '@' )
 {
     (void) READ_CURRENT(*buf);
     WaitInput(buf);
     if ( CURRENT(*buf) == 'J' )
     {
  *ptr++ = '\n';
  *ptr   = 0;
  (void) READ_CURRENT(*buf);
  return;
     }
     else if ( CURRENT(*buf) != '@' )
  *ptr++ = '^';
     *ptr++ = READ_CURRENT(*buf);
 }
 else
     *ptr++ = READ_CURRENT(*buf);
    } while ( 1 );
}


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

*F  StoreInput( <str>, <len> ) . . . . . . . . . store input for later usage
*/

static struct _storage
{
    String      buffer;
    Int         size;
    Int         len;
}
Storage = { 0, 0, 0 };

void StoreInput (
    String      str,
    Int         len)
{
    if ( Storage.buffer == 0 )
    {
 Storage.buffer = XtMalloc(4096);
 Storage.size   = 4096;
    }
    if ( Storage.size <= Storage.len + len )
    {
 Storage.size  += ((len/4096+1) * 4096);
 Storage.buffer = XtRealloc( Storage.buffer, Storage.size );
    }
    memcpy( Storage.buffer+Storage.len, str, len );
    Storage.len += len;
}


/****************************************************************************
**
*F  ProcessStoredInput( <state> ) . . . . . . . . .  feed stored input to gap
*/

static Char InputCookie = 'A';

void ProcessStoredInput (
    Int             state)
{
    String          ptr;
    String          free;
    Int             len;
    static Boolean  inProgress = False;

    /* if we are already processing input do not start again */
    if ( inProgress || state != 0 )
 return;

    /* if gap is not accepting input return */
    if ( GapState != GAP_INPUT && GapState != GAP_ERROR )
 return;

    /* if no input is waiting return */
    if ( Storage.len == 0 && *ScreenSizeBuffer == 0 )
 return;

    /* otherwise make sure that gap does not want to tell use something */
again:
    if ( HAS_INPUT(InBuffer) )
 GapOutput( 0, 0, 0 );
    if ( GapState != GAP_INPUT && GapState != GAP_ERROR )
 return;

    /* send '@yN' and wait for ACK '@sN' */
    if ( InputCookie++ == 'Z' )  InputCookie = 'A';
    WriteGap( "@y", 2 );
    WriteGap( &InputCookie, 1 );
    WaitInput(&InBuffer);
    if ( CURRENT(InBuffer) != '@' )
 goto again;
    WaitInput2(&InBuffer);
    if ( LOOK_AHEAD(InBuffer) != 's' )
 goto again;
    (void)READ_CURRENT(InBuffer);
    (void)READ_CURRENT(InBuffer);
    WaitInput(&InBuffer);
    if ( READ_CURRENT(InBuffer) != InputCookie )
 goto again;

    /* if the screen was resized,  process resize command first */
    if ( *ScreenSizeBuffer != 0 )
    {
 WriteGap( ScreenSizeBuffer, strlen(ScreenSizeBuffer) );
 *ScreenSizeBuffer = 0;
 return;
    }

    /* start processing input,  check reaction of gap */
    inProgress = True;
    len = Storage.len;
    free = ptr = Storage.buffer;
    while ( 0 < len )
    {
 WriteGap( ptr, 1 );  len--;  ptr++;
 if (    ptr[-1] == '\n'
      || ptr[-1] == '\r'
      || (free<ptr-1 && ptr[-2]=='@' && ptr[-1]=='M')
      || (free<ptr-1 && ptr[-2]=='@' && ptr[-1]=='J')
     )
     break;
 if (    ! QuitGapCtrlD && GapState == GAP_INPUT 
      && ptr[-1] == '@' && ptr[0] == 'D' )
 {
     WriteGap( "F@H", 3 );
     len--;
     ptr++;
 }
    }

    /* create new buffer,  store remaining input, and free old */
    inProgress = False;
    if ( len <= Storage.size )
    {
 Storage.len = len;
 for ( ;  0 < len;  len-- )
     *free++ = *ptr++;
    }
    else
    {
 Storage.size   = ( 4096 < len ) ? len : 4096;
 Storage.buffer = XtMalloc(Storage.size);
 memcpy( Storage.buffer, ptr, len );
 Storage.len = len;
 XtFree(free);
    }
    if ( GapState == GAP_HELP )
 ProcessStoredInput(0);
}


/****************************************************************************
**
*F  SimulateInput( <str> )  . . . . . . . . . .  enter a line as command line
*/

void SimulateInput (
    String  str)
{
    Int     pos;

    /* if <GAP> is not accepting input,  discard line */
    if ( GapState != GAP_INPUT && GapState != GAP_ERROR )
 return;

    /* ok, do it.  get current cursor position */
    pos = GTPosition(GapTalk) - LastLine;
    StoreInput( "@A@K", 4 );
    StoreInput( str, strlen(str) );
    StoreInput( "@Y@A", 4 );
    while ( 0 < pos-- )
 StoreInput( "@F", 2 );
    ProcessStoredInput(0);
}


/****************************************************************************
**
*F  KeyboardInput( <str>, <len> ) . . . . . . . . . .  process keyboard input
*/

Boolean PlayingBack = False;
FILE * Playback = 0;

int PlaybackFile (
    String      str)
{
    if ( Playback != 0 ) {
 fclose(Playback);
    }
    Playback = fopen( str, "r" );
    if ( Playback != 0 ) {
 PlayingBack = True;
    }
    else {
 PlayingBack = False;
    }
    return PlayingBack;
}

int ResumePlayback ( void )
{
    if ( PlayingBack || Playback == 0 )
 return False;
    PlayingBack = True;
    return True;
}

void KeyboardInput (
    String      str,
    Int         len)
{
    char        buf[1025];

#ifndef EXIT_ON_DOUBLE_CTR_C
    static Int ltime = 0;
    Int         ntime;  
#endif

    /* read playback file */
    if ( PlayingBack && GapState == GAP_INPUT ) {
 if ( *str == 'q' || *str == 'Q' ) {
     fclose(Playback);
     PlayingBack = False;
     Playback = 0;
     StoreInput( "\"Playback STOPPED\";;\n", 21 );
 }
 else if ( *str=='z' || *str=='Z' || *str=='y' || *str=='Y' ) {
     PlayingBack = False;
     StoreInput( "\"Playback SUPENDED\";;\n", 22 );
 }
 else {
     if ( fgets( buf, 1024, Playback ) == 0 ) {
  fclose(Playback);
  PlayingBack = False;
  Playback = 0;
     }
     else {
  StoreInput( buf, strlen(buf) );
  if ( feof(Playback) ) {
      fclose(Playback);
      PlayingBack = False;
      Playback = 0;
  }
     }
     if ( ! PlayingBack )
  StoreInput( "\"Playback ENDED\";;\n", 19 );
 }
    }

    /* handle help mode directly */
    else if ( GapState == GAP_HELP )
    {
 if ( HAS_INPUT(InBuffer) || HAS_INPUT(InBuffer) )
     GapOutput( 0, 0, 0 );
 if ( GapState != GAP_HELP )
 {
     KeyboardInput( str, len );
     return;
 }

 /* send '@yN' and wait for ACK '@sN' */
 if ( InputCookie++ == 'Z' )  InputCookie = 'A';
 WriteGap( "@y", 2 );
 WriteGap( &InputCookie, 1 );
 WaitInput(&InBuffer);
 if ( CURRENT(InBuffer) != '@' )
 {
     GapOutput( 0, 0, 0 );
     KeyboardInput( str, len );
     return;
 }
 WaitInput2(&InBuffer);
 if ( LOOK_AHEAD(InBuffer) != 's' )
 {
     GapOutput( 0, 0, 0 );
     KeyboardInput( str, len );
     return;
 }
 (void)READ_CURRENT(InBuffer);
 (void)READ_CURRENT(InBuffer);
 if ( READ_CURRENT(InBuffer) != InputCookie ) {
     GapOutput( 0, 0, 0 );
     KeyboardInput( str, len );
     return;
 }

 /* write a character and start again */
 WriteGap( str, 1 );
 if ( *str == '@' && 1 < len )
 {
     WriteGap( str+1, 1 );
     str++;
     len--;
 }
 str++;
 len--;
 if ( 0 < len )
     KeyboardInput( str, len );
 return;
    }

    /* consume input */
    else if ( PlayingBack && GapState == GAP_RUNNING ) {
 ;
    }
    else {
    while ( 0 < len )
    {

 /* handle <CTR-C> */
 if ( 2 <= len && *str == '@' && str[1] == 'C' )
 {
#           ifndef EXIT_ON_DOUBLE_CTR_C
         while ( 2 <= len && *str == '@' && str[1] == 'C' )
  {
      str += 2;
      len -= 2;
  }
  ntime = (int) time(0);
  if ( 2 < ntime - ltime )
      InterruptGap();
  ltime = ntime;
#           else
  InterruptGap();
  str += 2;
  len -= 2;
#           endif
 }

 /* otherwise store it */
 else
 {
     StoreInput( str, 1 );
     len--;
     str++;
 }
    }
    }

    /* try to process input */
    ProcessStoredInput(0);
}


/****************************************************************************
**
*F  CheckCaretPos( <new>, <old> ) . . . . . . . . . . .  check caret movement
*/

Int CheckCaretPos (
    Int     new,
    Int     old)
{
    /* if <LastLine> is -1,  then gap is running,  ignore move */
    if ( LastLine < 0 )
 return 0;

    /* if the new position is before the last line,  ignore move */
    else if ( new < LastLine )
 return 0;

    /* otherwise move in the correct direction */
    else if ( new < old )
    {
 while ( new++ < old )
     WriteGap( "@B", 2 );
 return 0;
    }
    else if ( old < new )
    {
 while ( old++ < new )
     WriteGap( "@F", 2 );
 return 0;
    }
    else
 return 0;
}


/****************************************************************************
**
*F  ParseInt( <buf>, <val> )  . . . . . . . . . . . . . . .  get a long value
*/

static Boolean ParseInt (
    struct _in_buf    * buf,
    Int               * val )
{
    Int                 mult;

    *val = 0;
    mult = 1;
    do
    {
 WaitInput(buf);
 if ( CURRENT(*buf) == '+' )
 {
     (void) READ_CURRENT(*buf);
     return True;
 }
 else if ( CURRENT(*buf) == '-' )
 {
     (void) READ_CURRENT(*buf);
     *val = -*val;
     return True;
 }
 else if ( '0' <= CURRENT(*buf) && CURRENT(*buf) <= '9' )
     *val += mult * (READ_CURRENT(*buf)-'0');
 else
     return False;
 mult = mult * 10;
    } while (1);
}


/****************************************************************************
**
*F  GapOutput( <cld>, <fid>, <id> ) . . . . . . . . . . . . handle gap output
*/

#undef  CTR
#define CTR(a) ( a & 0x1f )

static char TBuf[SIZE_BUFFER];

void GapOutput (
    XtPointer       cld,
    int           * fid,
    XtInputId       id)
{
    char            ch;
    Int             special;
    Int             len;

    /* wait a while for input */
    HAS_INPUT(InBuffer);
    HAS_INPUT(InBuffer);
    HAS_INPUT(InBuffer);

    /* special code for 'Exec' */
    if ( ExecRunning )
    {
 DEBUG( D_COMM, ("GapOutput: exec still active\n") );
 len = 0;
 while ( HAS_BUFFERED(InBuffer) && len < SIZE_BUFFER-3 )
 {
     /* '@' is special */
     if ( CURRENT(InBuffer) == '@' )
     {
  (void) READ_CURRENT(InBuffer);
  WaitInput(&InBuffer);
  if ( CURRENT(InBuffer) == 'm' )
  {

      /* get ride of any output left over */
      if ( 0 < len )
      {
   TBuf[len] = 0;
   GTReplaceText( GapTalk, TBuf, len );
   if ( SpyMode )
       fwrite( TBuf, 1, len, stderr );
      }

      /* collect output 'TBuf' in case it is not "mAgIc" */
      len = 0;
      TBuf[len++] = '@';
      TBuf[len++] = 'm';
      (void)READ_CURRENT(InBuffer);
      WaitInput(&InBuffer);
      if ( CURRENT(InBuffer) != 'A' )  continue;
      (void)READ_CURRENT(InBuffer);
      TBuf[len++] = 'A';
      WaitInput(&InBuffer);
      if ( CURRENT(InBuffer) != 'g' )  continue;
      (void)READ_CURRENT(InBuffer);
      TBuf[len++] = 'g';
      WaitInput(&InBuffer);
      if ( CURRENT(InBuffer) != 'I' )  continue;
      (void)READ_CURRENT(InBuffer);
      TBuf[len++] = 'I';
      WaitInput(&InBuffer);
      if ( CURRENT(InBuffer) != 'c' )  continue;
      (void)READ_CURRENT(InBuffer);
      len = 0;
      ExecRunning = False;
      DEBUG( D_COMM, ("GapOutput: %s: '%s'\n",
                           "leaving exec loop, input remaining",
             InBuffer.buffer+InBuffer.pos) );
      goto end_exec_loop;

  }
  else
  {
      TBuf[len++] = '@';
      continue;
  }
     }
     
     /* store input */
     else
  TBuf[len++] = READ_CURRENT(InBuffer);
 }
 TBuf[len] = 0;
 GTReplaceText( GapTalk, TBuf, len );
        if ( SpyMode )
     fwrite( TBuf, 1, len, stderr );
 return;
    }
end_exec_loop:
 
    /* process gap output */
    while ( HAS_BUFFERED(InBuffer) )
    {
 /* '@' is special */
 if ( CURRENT(InBuffer) == '@' )
 {
     (void) READ_CURRENT(InBuffer);
     WaitInput(&InBuffer);
     if ( 'A' <= CURRENT(InBuffer) && CURRENT(InBuffer) <= 'Z' )
     {
  special = 0;
  ch = READ_CURRENT(InBuffer);
  ch = CTR(ch);
     }
     else if ( CURRENT(InBuffer) == '@' )
     {
  special = 0;
  ch = READ_CURRENT(InBuffer);
     }
     else if ( CURRENT(InBuffer) == 'z' )
     {
  (void)READ_CURRENT(InBuffer);
  ExecRunning = True;
  DEBUG( D_COMM, ("GapOutput: entering exec loop\n") );
  GapOutput( cld, fid, id );
  return;
     }
  
     else
     {
  special = 1;
  ch = READ_CURRENT(InBuffer);
     }
 }
 else
 {
     special = 0;
     ch = READ_CURRENT(InBuffer);
 }

 /* process window commands */
 if ( special )
 {

     /* '1' to '6' are garbage */
     if ( '1' <= ch && ch <= '6' )
     {
  Int size;
  ParseInt( &InBuffer, &size );
  UpdateMemoryInfo( (int) (ch-'0'), size );
     }

     /* '!','"','#','$','%','&' are garbage */
     else if ( '!' <= ch && ch <= '&' ) {
  Int size;
  ParseInt( &InBuffer, &size );
     }

     /* 'i' means gap is waiting for input */
     else if ( ch == 'i' )
     {
  LastLine = GTPosition(GapTalk);
  GapState = GAP_INPUT;
  UpdateMenus(GapState);
  UpdateXCMDS(True);
  ProcessStoredInput(0);
     }

     /* 'e' means gap is waiting for error input */
     else if ( ch == 'e' )
     {
  LastLine = GTPosition(GapTalk);
  GapState = GAP_ERROR;
  UpdateMenus(GapState);
  UpdateXCMDS(True);
  ProcessStoredInput(0);
     }

     /* 'r' is the current input line */
     else if ( ch == 'r' )
     {
  ReadLine(&InBuffer);
  GTSetPosition( GapTalk, LastLine );
  GTReplaceText( GapTalk, GapBuffer, strlen(GapBuffer) );
  if ( SpyMode )
  {
      fwrite( GapBuffer, 1, strlen(GapBuffer), stderr );
  }
  GapState = GAP_RUNNING;
  UpdateMenus(GapState);
  UpdateXCMDS(False);
  ProcessStoredInput(1);
  LastLine = -1;
     }
     
     /* 'x' no text at current line */
     else if ( ch == 'x' )
     {
  GTSetPosition( GapTalk, LastLine );
  GTReplaceText( GapTalk, "", 0 );
  GapState = GAP_RUNNING;
  UpdateMenus(GapState);
  UpdateXCMDS(True);
  LastLine = -1;
     }
     
     /* 'c' completion output started */
     else if ( ch == 'c' )
     {
  GapState = GAP_RUNNING;
  UpdateMenus(GapState);
  UpdateXCMDS(True);
  LastLine = -1;
     }
     
     /* 'h' help output started */
     else if ( ch == 'h' )
     {
  GapState = GAP_HELP;
  UpdateMenus(GapState);
  UpdateXCMDS(False);
  LastLine = -1;
     }
     
     /* 'w' is a window command */
     else if ( ch == 'w' )
     {
  long i;
  long    m;
  char  * ptr;
  char  * cmd;

  len = 0;
  WaitInput(&InBuffer);
  ch = READ_CURRENT(InBuffer);
  for ( len = 0, m = 1;  '0' <= ch && ch <= '9';  m *= 10 ) {
      len += (ch-'0') * m;
      WaitInput(&InBuffer);
      ch = READ_CURRENT(InBuffer);
  }
  ptr = cmd = XtMalloc(len+1);
  i   = len;
         while ( 0 < i )
  {
      WaitInput(&InBuffer);
      while ( HAS_INPUT(InBuffer) && 0 < i )
      {
   *ptr++ = READ_CURRENT(InBuffer);
   i--;
      }
  }
  *ptr++ = 0;
  GapWindowCmd( cmd, len );
  XtFree(cmd);
     }

     /* ignore 'n' for the moment */
     else if ( ch == 'n' )
  ch = 'n';

     /* ignore 'f' for the moment */
     else if ( ch == 'f' )
  ch = 'f';

     /* ignore 's',  see 'SimulateInput' */
     else if ( ch == 's' ) {
  WaitInput(&InBuffer);
  (void)READ_CURRENT(InBuffer);
  continue;
     }
 }

 /* collect normal characters and display them */
 else if ( ' ' <= ch && ch < 127 && GapState == GAP_RUNNING )
 {
     TBuf[0] = ch;
     for ( len = 1;  len<SIZE_BUFFER && HAS_BUFFERED(InBuffer); )
  if ( CURRENT(InBuffer) == '@' )
  {
      if ( LOOK_AHEAD(InBuffer) == 'n' )
      {
   (void)READ_CURRENT(InBuffer);
   /* WaitInput(&InBuffer); */
   (void)READ_CURRENT(InBuffer);
      }
      else if ( LOOK_AHEAD(InBuffer) == 'f' )
      {
   (void)READ_CURRENT(InBuffer);
   /* WaitInput(&InBuffer); */
   (void)READ_CURRENT(InBuffer);
      }
      else if ( LOOK_AHEAD(InBuffer) == 'J' )
      {
   (void)READ_CURRENT(InBuffer);
   /* WaitInput(&InBuffer); */
   (void)READ_CURRENT(InBuffer);
   TBuf[len++] = '\n';
      }
      else
   break;
  }
  else if ( ' '<=CURRENT(InBuffer) && CURRENT(InBuffer)<127 )
      TBuf[len++] = READ_CURRENT(InBuffer);
         else
      break;
     GTReplaceText( GapTalk, TBuf, len );
 }

 /* collect normal characters and display them */
 else if ( ' ' <= ch && ch < 127 && GapState != GAP_RUNNING )
 {
     TBuf[0] = ch;
     for ( len = 1;  len<SIZE_BUFFER && HAS_INPUT(InBuffer);  len++ )
  if ( CURRENT(InBuffer) == '@' )
      break;
  else if ( ' '<=CURRENT(InBuffer) && CURRENT(InBuffer)<127 )
      TBuf[len] = READ_CURRENT(InBuffer);
         else
      break;
     GTReplaceText( GapTalk, TBuf, len );
 }

 /* carriage return */
 else if ( ch == '\n' )
 {
     if ( GapState != GAP_INPUT && GapState != GAP_ERROR )
  GTReplaceText( GapTalk, &ch, 1 );
 }

 /* <CTR-G> rings a bell */
 else if ( ch == CTR('G') )
     GTBell(GapTalk);

 /* <CTR-H> moves to the left */
 else if ( ch == CTR('H') )
     GTMoveCaret( GapTalk, -1 );

 /* ignore anything else */
 else 
     ch = ch;
    }
}


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

*F * * * * * * * * * * * * starting/stopping gap + * * * * * * * * * * * * *
*/



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

*F  KillGap() . . . . . . . . . . . . . . . . . . . . .  kill the running gap
*/

void KillGap ()
{
    if ( GapPID != -1 )
    {
 close(ToGap);
        kill( GapPID, SIGKILL );
    }
}


/****************************************************************************
**
*F  InterruptGap()  . . . . . . . . . . . . . . . .  interrupt the running gap
*/

void InterruptGap ()
{
    if ( GapPID != -1 )
        kill( GapPID, SIGINT );
}


/****************************************************************************
**
*F  OpenPty( <master>, <slave> ) . . . . . .  open a pty master/slave pair
*/


#ifdef HAVE_OPENPTY

static UInt OpenPty(int * master, int * slave)
{
    /* openpty is available on OpenBSD, NetBSD and FreeBSD, Mac OS X,
       Cygwin, Interix, OSF/1 4 and 5, and glibc (since 1998), and hence
       on most modern Linux systems. See also:
       https://www.gnu.org/software/gnulib/manual/html_node/openpty.html */

    return (openpty(master, slave, NULL, NULL, NULL) < 0);
}

#elif defined(HAVE_POSIX_OPENPT)

static UInt OpenPty(int * master, int * slave)
{
    /* Attempt to use POSIX 98 pseudo ttys. Opening a master tty is done
       via posix_openpt, which is available on virtually every current
       UNIX system; indeed, according to gnulib, it is available on at
       least the following systems:
         - glibc >= 2.2.1 (released January 2001; but is a stub on GNU/Hurd),
         - Mac OS X >= 10.4 (released April 2005),
         - FreeBSD >= 5.1 (released June 2003),
         - NetBSD >= 3.0 (released December 2005),
         - AIX >= 5.2 (released October 2002),
         - HP-UX >= 11.31 (released February 2007),
         - Solaris >= 10 (released January 2005),
         - Cygwin >= 1.7 (released December 2009).
       Systems lacking posix_openpt (in addition to older versions of
       the systems listed above) include:
         - OpenBSD
         - Minix 3.1.8
         - IRIX 6.5
         - OSF/1 5.1
         - mingw
         - MSVC 9
         - Interix 3.5
         - BeOS
       */

    *master = posix_openpt(O_RDWR | O_NOCTTY);
    if (*master < 0) {
        fputs("OpenPty: posix_openpt failed\n");
        return 1;
    }

    if (grantpt(*master)) {
        fputs("OpenPty: grantpt failed\n");
        goto error;
    }
    if (unlockpt(*master)) {
        close(*master);
        fputs("OpenPty: unlockpt failed\n");
        goto error;
    }

    *slave = open(ptsname(*master), O_RDWR, 0);
    if (*slave < 0) {
        fputs("OpenPty: opening slave tty failed\n");
        goto error;
    }
    return 0;

error:
    close(*master);
    return 1;
}

#else

static UInt OpenPty(int * master, int * slave)
{
    fputs("no pseudo tty support available\n");
    return 1;
}

#endif


/****************************************************************************
**
*F  StartGapProcess( <name>, <argv> ) . . . start a gap subprocess using ptys
*/

static void GapStatusHasChanged (int signo)
{
    int             w;

    /* if the child was stopped return */
    if ( waitpid( -1, &w, WNOHANG | WUNTRACED ) != GapPID || WIFSTOPPED(w) )
 return;
#   ifdef DEBUG_ON
        fputs( "gap status has changed, leaving xgap\n", stderr );
        fprintf( stderr,"Signal: %d\n",WTERMSIG(w));
#   endif
    exit(1);
}

int StartGapProcess (
    String          name,
    String          argv[])
{
    Int             j;       /* loop variables                  */
    char            c[10];   /* buffer for communication        */
    int             master;  /* pipe to GAP                     */
    int             n;       /* return value of 'select'        */
    int             slave;   /* pipe from GAP                   */
    /* struct */ fd_set   fds;     /* for 'select'                    */
    struct timeval  timeout; /* time to wait for aknowledgement */

#   if HAVE_TERMIOS_H
        struct termios  tst; /* old and new terminal state      */
#   else
#     if HAVE_TERMIO_H
        struct termio   tst; /* old and new terminal state      */
#     else
        struct sgttyb   tst; /* old and new terminal state      */
#     endif
#   endif

    /* open pseudo terminal for communication with gap */
    if (OpenPty(&master, &slave))
    {
        fprintf( stderr, "open pty failed (errno %d)\n", errno );
        exit(1);
    }
#   if HAVE_TERMIOS_H
        if ( tcgetattr( slave, &tst ) == -1 )
        {
            fputs( "tcgetattr on slave pty failed\n", stderr );
            exit(1);
        }
        tst.c_cc[VINTR] = 0377;
        tst.c_cc[VQUIT] = 0377;
        tst.c_iflag    &= ~(INLCR|ICRNL);
        tst.c_cc[VMIN]  = 1;
        tst.c_cc[VTIME] = 0;
        tst.c_lflag    &= ~(ECHO|ICANON);
        if ( tcsetattr( slave, TCSANOW, &tst ) == -1 )
        {
            fputs( "tcsetattr on slave pty failed\n", stderr );
            exit(1);
        }
#   else
#     if HAVE_TERMIO_H
        if ( ioctl( slave, TCGETA, &tst ) == -1 )
 {
     fputs( "ioctl TCGETA on slave pty failed\n", stderr );
     exit(1);
 }
        tst.c_cc[VINTR] = 0377;
        tst.c_cc[VQUIT] = 0377;
        tst.c_iflag    &= ~(INLCR|ICRNL);
        tst.c_cc[VMIN]  = 1;
        tst.c_cc[VTIME] = 0;   
        /* Note that this is at least on Linux dangerous! 
           Therefore, we now have the HAVE_TERMIOS_H section for POSIX
           Terminal control. */

        tst.c_lflag    &= ~(ECHO|ICANON);
        if ( ioctl( slave, TCSETAW, &tst ) == -1 )
        {
     fputs( "ioctl TCSETAW on slave pty failed\n", stderr );
     exit(1);
 }
#     else
        if ( ioctl( slave, TIOCGETP, (char*)&tst ) == -1 )
        {
     if ( ttydev )
       fprintf( stderr, "ioctl TIOCGETP on slave pty failed (%s)\n",
         ttydev );
     else
       fputs( "ioctl TIOCGETP on slave pty failed\n", stderr );
     exit(1);
        }
        tst.sg_flags |= RAW;
        tst.sg_flags &= ~ECHO;
        if ( ioctl( slave, TIOCSETN, (char*)&tst ) == -1 )
        {
            fputs( "ioctl on TIOCSETN slave pty failed\n", stderr );
     exit(1);
 }
#endif
#endif

    /* set input to non blocking operation */
    if ( fcntl( master, F_SETFL, O_NDELAY ) < 0 )
    {
        fputs( "Panic: cannot set non blocking operation.\n", stderr );
        exit(1);
    }

    /* fork to gap, dup pipe to stdin and stdout */
    GapPID = fork();
    if ( GapPID == 0 )
    {
        dup2( slave, 0 );
        dup2( slave, 1 );
        /* The following is necessary because otherwise the GAP process
           will ignore the SIGINT signal: */

        signal( SIGINT, SIG_DFL );
#       ifdef SYS_HAS_EXECV_CCHARPP
            execv( name, (const char**) argv );
#       else
            execv( name, (void*) argv );
#       endif
        if (write( 1, "@-", 2) < 2) fputs("Child: Cannot write @-", stderr);
        close(slave);
        _exit(1);
    }
    ToGap   = master;
    FromGap = master;

    /* check if the fork was successful */
    if ( GapPID == -1 )
    {
        fputs( "Panic: cannot fork to subprocess.\n", stderr );
        exit(1);
    }

    /* wait at least 60 sec before giving up */
    timeout.tv_sec  = 60;
    timeout.tv_usec = 0;

    /* wait for an aknowledgement (@p) from the gap subprocess */
    j = 0;
    while ( j < 10 && c[j-1] != '.' )
    {

        /* set <FromGap> port for listen */
#       ifdef FD_SET
     FD_ZERO(&fds);
     FD_SET( FromGap, &fds );
#       else
        {
     Int     i;

            for ( i = FromGap/sizeof(fds.fds_bits); 0 <= i; i-- )
                fds.fds_bits[i] = 0;
            fds.fds_bits[FromGap/sizeof(fds.fds_bits)] =
                                   ( 1 << (FromGap % sizeof(fds.fds_bits)) );
        }
#       endif

        /* use 'select' to check port */
        if ( (n = select(FromGap+1, &fds, 0, 0, &timeout)) == -1 )
        {
            kill( GapPID, SIGKILL );
            perror("select failed");
            exit(1);
        }
        else if ( n == 0 )
        {
            kill( GapPID, SIGKILL );
            fputs("Panic: cannot establish communication with gap.", stderr);
            exit(1);
        }
        else
            ReadGap( &(c[j++]), 1 );
    }

    /* check if we got "@p" */
    if ( c[j-1] != '.' || strncmp( c, "@p", 2 ) )
    {
        if ( ! strncmp( c, "@-", 2 ) )
        {
            fputs( "Panic: cannot start subprocess ", stderr );
            fputs( name, stderr );
            fputs( ".\n", stderr );
        }
        else
        {
            strcpy( c+3, "'\n" );
            fputs( "Panic: cannot talk with gap, got '", stderr );
            fputs( c, stderr );
            kill( GapPID, SIGKILL );
        }
        exit(1);
    }

    /* if the gap dies,  stop program */
    signal( SIGCHLD, GapStatusHasChanged );
    InBuffer.pos = InBuffer.len = 0;
    return FromGap;
}


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

*E  pty.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ends here
*/

91%


¤ Dauer der Verarbeitung: 0.28 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.