/**************************************************************************** ** *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"
#ifdef HAVE_OPENPTY #ifdefined(HAVE_UTIL_H) #include <util.h> /* for openpty() on Mac OS X, OpenBSD and NetBSD */ #elifdefined(HAVE_LIBUTIL_H) #include <libutil.h> /* for openpty() on FreeBSD */ #elifdefined(HAVE_PTY_H) #include <pty.h> /* for openpty() on Cygwin, Interix, OSF/1 4 and 5 */ #endif #endif
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;
}
}
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;
}
}
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;
}
/* handle help mode directly */ elseif ( 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;
}
/* otherwise store it */ else
{
StoreInput( str, 1 );
len--;
str++;
}
}
}
/* try to process input */
ProcessStoredInput(0);
}
/**************************************************************************** ** *F CheckCaretPos( <new>, <old> ) . . . . . . . . . . . check caret movement
*/ Int CheckCaretPos ( Intnew, 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 */ elseif ( new < LastLine ) return 0;
/* otherwise move in the correct direction */ elseif ( new < old )
{ while ( new++ < old )
WriteGap( "@B", 2 ); return 0;
} elseif ( 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); returnTrue;
} elseif ( CURRENT(*buf) == '-' )
{
(void) READ_CURRENT(*buf);
*val = -*val; returnTrue;
} elseif ( '0' <= CURRENT(*buf) && CURRENT(*buf) <= '9' )
*val += mult * (READ_CURRENT(*buf)-'0'); else returnFalse;
mult = mult * 10;
} while (1);
}
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);
} elseif ( CURRENT(InBuffer) == '@' )
{
special = 0;
ch = READ_CURRENT(InBuffer);
} elseif ( 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 );
}
/**************************************************************************** ** *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);
}
#elifdefined(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;
}
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
*/ staticvoid 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, (constchar**) 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;
¤ 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.0.28Bemerkung:
(vorverarbeitet)
¤
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.