GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
/****************************************************************************1**2*W pty.c XGAP source Frank Celler3**4**5*Y Copyright 1995-1997, Lehrstuhl D fuer Mathematik, RWTH Aachen, Germany6*Y Copyright 1997, Frank Celler, Huerth, Germany7**8** This file contains all the code for handling pseudo ttys. 'GetMasterPty'9** is based on code from 'xterm'.10**11** GAP is started in a special mode that will mask special characters. The12** following '@' sequences produced by GAP are recoginzed:13**14** 'pX.' package mode version X15** '@' a single '@'16** 'A'..'Z' a control character17** '1','2','3','4','5','6' full garbage collection information18** '!','"','#','$','%','&' partial garbage collection information19** 'e' gap is waiting for error input20** 'c' completion started21** 'f' error output22** 'h' help started23** 'i' gap is waiting for input24** 'm' end of 'Exec'25** 'n' normal output26** 'r' the current input line follows27** 'sN' ACK for '@yN'28** 'w' a window command follows29** 'x' the current input line is empty30** 'z' start of 'Exec'31*/32#include "utils.h"3334#include "gaptext.h"35#include "xcmds.h"36#include "xgap.h"3738#include "pty.h"394041/****************************************************************************42**4344*F * * * * * * * * * * * * * * local variables * * * * * * * * * * * * * * *45*/464748/****************************************************************************49**5051*V GapPID . . . . . . . . . . . . . . . . . . . . . . . . gap subprocess id52*/53static int GapPID = -1;545556/****************************************************************************57**58*V FromGap . . . . . . . . . . . . . . . . . . . . . . for messages from gap59*/60static int FromGap;616263/****************************************************************************64**65*V ToGap . . . . . . . . . . . . . . . . . . . . . . . . for messages to gap66*/67static int ToGap;686970/* * * * * * * * * * * * * * global variables * * * * * * * * * * * * * * */717273/****************************************************************************74**7576*V QuitGapCtrlD . . . . . . . . . . . . . . . . . . . . . . . quit on CTR-D77*/78Boolean QuitGapCtrlD = FALSE;798081/****************************************************************************82**83*V ScreenSizeBuffer . . . . . . . . . . . . . . screen size change command84*/85char ScreenSizeBuffer[1024] = { 0 };868788/****************************************************************************89**90*V ExecRunning . . . . . . . . . . . . . . . . . . external program running91*/92Boolean ExecRunning = False;939495/****************************************************************************96**9798*F * * * * * * * * * * * * communication with GAP * * * * * * * * * * * * *99*/100101102/****************************************************************************103**104105*F ReadGap( <line>, <len> ) . . . . . . . . . . . . . . . . read gap output106*/107#ifdef DEBUG_ON108109Int READ_GAP ( file, where, line, len )110String file;111Int where;112String line;113Int len;114{115Int n;116Int old;117118if ( Debug & D_COMM )119{120printf( "%04d:%s: ReadGap( buf, %d ) = ", where, file, len );121fflush( stdout );122}123if ( len < 0 )124{125len = read( FromGap, line, -len );126if ( Debug & D_COMM )127{128if ( len == -1 )129fprintf( stdout, "-1: no input\n" );130else131{132fprintf( stdout, "%d: '", len );133fwrite( line, 1, len, stdout );134fprintf( stdout, "'\n" );135}136fflush( stdout );137}138return len;139}140else141{142old = len;143while ( 0 < len )144{145while ( ( n = read( FromGap, line, len ) ) < 0 )146;147line = line + n;148len = len - n;149}150if ( Debug & D_COMM )151{152fprintf( stdout, "%d: '", old );153fwrite( line-old, 1, old, stdout );154fprintf( stdout, "'\n" );155fflush( stdout );156}157return old;158}159}160161#else162163Int ReadGap ( line, len )164String line;165Int len;166{167Int n;168Int old;169170if ( len < 0 )171return read( FromGap, line, -len );172else173{174old = len;175while ( 0 < len )176{177while ( ( n = read( FromGap, line, len ) ) < 0 )178;179line = line + n;180len = len - n;181}182return old;183}184}185186#endif187188189/****************************************************************************190**191*F WriteGap( <line>, <len> ) . . . . . . . . . . . . . . . . write gap input192*/193extern int errno;194195#ifdef DEBUG_ON196197void WRITE_GAP ( file, where, line, len )198String file;199Int where;200String line;201Int len;202{203Int res;204205if ( Debug & D_COMM )206{207printf( "%04d:%s: WriteGap( %d ) = '", where, file, len );208fwrite( line, 1, len, stdout );209fprintf( stdout, "'\n" );210fflush( stdout );211}212while ( 0 < len )213{214res = write( ToGap, line, len );215if ( res < 0 )216{217if ( errno == EAGAIN )218continue;219perror( "WriteGap" );220KillGap();221exit(1);222}223len -= res;224line += res;225}226}227228#else229230void WriteGap ( line, len )231String line;232Int len;233{234Int res;235236while ( 0 < len )237{238res = write( ToGap, line, len );239if ( res < 0 )240{241if ( errno == EAGAIN )242continue;243perror( "WriteGap" );244KillGap();245exit(1);246}247len -= res;248line += res;249}250}251252#endif253254255/****************************************************************************256**257258*V InBuffer . . . . . . . . . . . . . . . . . . . . . buffer of gap output259*/260#define SIZE_BUFFER 16000261262static struct _in_buf263{264char buffer[SIZE_BUFFER];265Int pos;266Int len;267}268InBuffer;269270271/****************************************************************************272**273*V GapBuffer . . . . . . . . . . . . . . . . temporary buffer for 'ReadLine'274*/275static char GapBuffer[SIZE_BUFFER];276277278/****************************************************************************279**280*V LastLine . . . . . . . . . . . . . . . . . . . . beginning of last line281*/282static Int LastLine;283284285/****************************************************************************286**287288*D CURRENT( <buf> ) . . . . . . . . . . . . . . . . . . . . current symbol289*/290#define CURRENT(buf) ((buf).buffer[(buf).pos])291292293/****************************************************************************294**295*D READ_CURRENT( <buf> ) . . . . . . . . . . . . . . consume current symbol296*/297#define READ_CURRENT(buf) ((buf).buffer[(buf).pos++])298299300/****************************************************************************301**302*D HAS_INPUT( <buf> ) . . . . . . . . . . . . . . . . . . . check for input303*/304#define HAS_INPUT(buf) ( ((buf).len <= (buf).pos) ? (buf).pos = 0, \305((buf).len=ReadGap((buf).buffer,-SIZE_BUFFER))>0 :\3061 )307308309/****************************************************************************310**311*D HAS_BUFFERED( <buf> ) . . . . . . . . . . . . . check for buffered input312*/313#define HAS_BUFFERED(buf) ( (buf).pos < (buf).len )314315316/****************************************************************************317**318*D LOOK_AHEAD( <buf> ) . . . look ahead if there is enough input, dont check319*/320#define LOOK_AHEAD(buf) ( ((buf).pos+1 < (buf).len ) ? \321((buf).buffer)[(buf).pos+1] : '\0' )322323324/****************************************************************************325**326327*F WaitInput( <buf> ) . . . . . . . . . . . . . . . wait for one character328*/329void WaitInput ( buf )330struct _in_buf * buf;331{332Int len;333334if ( buf->len <= buf->pos )335{336buf->pos = 0;337ReadGap( buf->buffer, 1 );338len = ReadGap( buf->buffer+1, -(SIZE_BUFFER-1) );339buf->len = (len < 0) ? 1 : len+1;340}341}342343344/****************************************************************************345**346*F WaitInput2( <buf> ) . . . . . . . . . . . . . . . wait for two characters347*/348void WaitInput2 ( buf )349struct _in_buf * buf;350{351Int len;352353if ( buf->len <= 1 + buf->pos )354{355if ( buf->pos+1 == buf->len )356{357*buf->buffer = buf->buffer[buf->pos];358buf->pos = 0;359ReadGap( buf->buffer+1, 1 );360len = ReadGap( buf->buffer+2, -(SIZE_BUFFER-2) );361buf->len = (len < 0) ? 2 : len+2;362}363else364{365buf->pos = 0;366ReadGap( buf->buffer, 2 );367len = ReadGap( buf->buffer+2, -(SIZE_BUFFER-2) );368buf->len = (len < 0) ? 2 : len+2;369}370}371}372373/****************************************************************************374**375*F ReadLine( <buf> ) . . . . . . . . . . . . . . . . . . . . . . read a line376*/377void ReadLine ( buf )378struct _in_buf * buf;379{380String ptr = GapBuffer;381382do383{384WaitInput(buf);385if ( CURRENT(*buf) == '\n' )386{387*ptr++ = READ_CURRENT(*buf);388*ptr = 0;389return;390}391else if ( CURRENT(*buf) == '\r' )392(void) READ_CURRENT(*buf);393else if ( CURRENT(*buf) == '@' )394{395(void) READ_CURRENT(*buf);396WaitInput(buf);397if ( CURRENT(*buf) == 'J' )398{399*ptr++ = '\n';400*ptr = 0;401(void) READ_CURRENT(*buf);402return;403}404else if ( CURRENT(*buf) != '@' )405*ptr++ = '^';406*ptr++ = READ_CURRENT(*buf);407}408else409*ptr++ = READ_CURRENT(*buf);410} while ( 1 );411}412413414/****************************************************************************415**416417*F StoreInput( <str>, <len> ) . . . . . . . . . store input for later usage418*/419static struct _storage420{421String buffer;422Int size;423Int len;424}425Storage = { 0, 0, 0 };426427void StoreInput ( str, len )428String str;429Int len;430{431if ( Storage.buffer == 0 )432{433Storage.buffer = XtMalloc(4096);434Storage.size = 4096;435}436if ( Storage.size <= Storage.len + len )437{438Storage.size += ((len/4096+1) * 4096);439Storage.buffer = XtRealloc( Storage.buffer, Storage.size );440}441memcpy( Storage.buffer+Storage.len, str, len );442Storage.len += len;443}444445446/****************************************************************************447**448*F ProcessStoredInput( <state> ) . . . . . . . . . feed stored input to gap449*/450static Char InputCookie = 'A';451452void ProcessStoredInput ( state )453Int state;454{455String ptr;456String free;457Int len;458static Boolean inProgress = False;459460/* if we are already processing input do not start again */461if ( inProgress || state != 0 )462return;463464/* if gap is not accepting input return */465if ( GapState != GAP_INPUT && GapState != GAP_ERROR )466return;467468/* if no input is waiting return */469if ( Storage.len == 0 && *ScreenSizeBuffer == 0 )470return;471472/* otherwise make sure that gap does not want to tell use something */473again:474if ( HAS_INPUT(InBuffer) )475GapOutput( 0, 0, 0 );476if ( GapState != GAP_INPUT && GapState != GAP_ERROR )477return;478479/* send '@yN' and wait for ACK '@sN' */480if ( InputCookie++ == 'Z' ) InputCookie = 'A';481WriteGap( "@y", 2 );482WriteGap( &InputCookie, 1 );483WaitInput(&InBuffer);484if ( CURRENT(InBuffer) != '@' )485goto again;486WaitInput2(&InBuffer);487if ( LOOK_AHEAD(InBuffer) != 's' )488goto again;489(void)READ_CURRENT(InBuffer);490(void)READ_CURRENT(InBuffer);491WaitInput(&InBuffer);492if ( READ_CURRENT(InBuffer) != InputCookie )493goto again;494495/* if the screen was resized, process resize command first */496if ( *ScreenSizeBuffer != 0 )497{498WriteGap( ScreenSizeBuffer, strlen(ScreenSizeBuffer) );499*ScreenSizeBuffer = 0;500return;501}502503/* start processing input, check reaction of gap */504inProgress = True;505len = Storage.len;506free = ptr = Storage.buffer;507while ( 0 < len )508{509WriteGap( ptr, 1 ); len--; ptr++;510if ( ptr[-1] == '\n'511|| ptr[-1] == '\r'512|| (free<ptr-1 && ptr[-2]=='@' && ptr[-1]=='M')513|| (free<ptr-1 && ptr[-2]=='@' && ptr[-1]=='J')514)515break;516if ( ! QuitGapCtrlD && GapState == GAP_INPUT517&& ptr[-1] == '@' && ptr[0] == 'D' )518{519WriteGap( "F@H", 3 );520len--;521ptr++;522}523}524525/* create new buffer, store remaining input, and free old */526inProgress = False;527if ( len <= Storage.size )528{529Storage.len = len;530for ( ; 0 < len; len-- )531*free++ = *ptr++;532}533else534{535Storage.size = ( 4096 < len ) ? len : 4096;536Storage.buffer = XtMalloc(Storage.size);537memcpy( Storage.buffer, ptr, len );538Storage.len = len;539XtFree(free);540}541if ( GapState == GAP_HELP )542ProcessStoredInput(0);543}544545546/****************************************************************************547**548*F SimulateInput( <str> ) . . . . . . . . . . enter a line as command line549*/550void SimulateInput ( str )551String str;552{553Int pos;554555/* if <GAP> is not accepting input, discard line */556if ( GapState != GAP_INPUT && GapState != GAP_ERROR )557return;558559/* ok, do it. get current cursor position */560pos = GTPosition(GapTalk) - LastLine;561StoreInput( "@A@K", 4 );562StoreInput( str, strlen(str) );563StoreInput( "@Y@A", 4 );564while ( 0 < pos-- )565StoreInput( "@F", 2 );566ProcessStoredInput(0);567}568569570/****************************************************************************571**572*F KeyboardInput( <str>, <len> ) . . . . . . . . . . process keyboard input573*/574Boolean PlayingBack = False;575FILE * Playback = 0;576577int PlaybackFile ( str )578String str;579{580if ( Playback != 0 ) {581fclose(Playback);582}583Playback = fopen( str, "r" );584if ( Playback != 0 ) {585PlayingBack = True;586}587else {588PlayingBack = False;589}590return PlayingBack;591}592593int ResumePlayback ( void )594{595if ( PlayingBack || Playback == 0 )596return False;597PlayingBack = True;598return True;599}600601void KeyboardInput ( str, len )602String str;603Int len;604{605char buf[1025];606607#ifndef EXIT_ON_DOUBLE_CTR_C608static Int ltime = 0;609Int ntime;610#endif611612/* read playback file */613if ( PlayingBack && GapState == GAP_INPUT ) {614if ( *str == 'q' || *str == 'Q' ) {615fclose(Playback);616PlayingBack = False;617Playback = 0;618StoreInput( "\"Playback STOPPED\";;\n", 21 );619}620else if ( *str=='z' || *str=='Z' || *str=='y' || *str=='Y' ) {621PlayingBack = False;622StoreInput( "\"Playback SUPENDED\";;\n", 22 );623}624else {625if ( fgets( buf, 1024, Playback ) == 0 ) {626fclose(Playback);627PlayingBack = False;628Playback = 0;629}630else {631StoreInput( buf, strlen(buf) );632if ( feof(Playback) ) {633fclose(Playback);634PlayingBack = False;635Playback = 0;636}637}638if ( ! PlayingBack )639StoreInput( "\"Playback ENDED\";;\n", 19 );640}641}642643/* handle help mode directly */644else if ( GapState == GAP_HELP )645{646if ( HAS_INPUT(InBuffer) || HAS_INPUT(InBuffer) )647GapOutput( 0, 0, 0 );648if ( GapState != GAP_HELP )649{650KeyboardInput( str, len );651return;652}653654/* send '@yN' and wait for ACK '@sN' */655if ( InputCookie++ == 'Z' ) InputCookie = 'A';656WriteGap( "@y", 2 );657WriteGap( &InputCookie, 1 );658WaitInput(&InBuffer);659if ( CURRENT(InBuffer) != '@' )660{661GapOutput( 0, 0, 0 );662KeyboardInput( str, len );663return;664}665WaitInput2(&InBuffer);666if ( LOOK_AHEAD(InBuffer) != 's' )667{668GapOutput( 0, 0, 0 );669KeyboardInput( str, len );670return;671}672(void)READ_CURRENT(InBuffer);673(void)READ_CURRENT(InBuffer);674if ( READ_CURRENT(InBuffer) != InputCookie ) {675GapOutput( 0, 0, 0 );676KeyboardInput( str, len );677return;678}679680/* write a character and start again */681WriteGap( str, 1 );682if ( *str == '@' && 1 < len )683{684WriteGap( str+1, 1 );685str++;686len--;687}688str++;689len--;690if ( 0 < len )691KeyboardInput( str, len );692return;693}694695/* consume input */696else if ( PlayingBack && GapState == GAP_RUNNING ) {697;698}699else {700while ( 0 < len )701{702703/* handle <CTR-C> */704if ( 2 <= len && *str == '@' && str[1] == 'C' )705{706# ifndef EXIT_ON_DOUBLE_CTR_C707while ( 2 <= len && *str == '@' && str[1] == 'C' )708{709str += 2;710len -= 2;711}712ntime = (int) time(0);713if ( 2 < ntime - ltime )714InterruptGap();715ltime = ntime;716# else717InterruptGap();718str += 2;719len -= 2;720# endif721}722723/* otherwise store it */724else725{726StoreInput( str, 1 );727len--;728str++;729}730}731}732733/* try to process input */734ProcessStoredInput(0);735}736737738/****************************************************************************739**740*F CheckCaretPos( <new>, <old> ) . . . . . . . . . . . check caret movement741*/742Int CheckCaretPos ( new, old )743Int new;744Int old;745{746/* if <LastLine> is -1, then gap is running, ignore move */747if ( LastLine < 0 )748return 0;749750/* if the new position is before the last line, ignore move */751else if ( new < LastLine )752return 0;753754/* otherwise move in the correct direction */755else if ( new < old )756{757while ( new++ < old )758WriteGap( "@B", 2 );759return 0;760}761else if ( old < new )762{763while ( old++ < new )764WriteGap( "@F", 2 );765return 0;766}767else768return 0;769}770771772/****************************************************************************773**774*F ParseInt( <buf>, <val> ) . . . . . . . . . . . . . . . get a long value775*/776static Boolean ParseInt (777struct _in_buf * buf,778Int * val )779{780Int mult;781782*val = 0;783mult = 1;784do785{786WaitInput(buf);787if ( CURRENT(*buf) == '+' )788{789(void) READ_CURRENT(*buf);790return True;791}792else if ( CURRENT(*buf) == '-' )793{794(void) READ_CURRENT(*buf);795*val = -*val;796return True;797}798else if ( '0' <= CURRENT(*buf) && CURRENT(*buf) <= '9' )799*val += mult * (READ_CURRENT(*buf)-'0');800else801return False;802mult = mult * 10;803} while (1);804}805806807/****************************************************************************808**809*F GapOutput( <cld>, <fid>, <id> ) . . . . . . . . . . . . handle gap output810*/811#undef CTR812#define CTR(a) ( a & 0x1f )813814static char TBuf[SIZE_BUFFER];815816void GapOutput ( cld, fid, id )817XtPointer cld;818int * fid;819XtInputId id;820{821char ch;822Int special;823Int len;824825/* wait a while for input */826HAS_INPUT(InBuffer);827HAS_INPUT(InBuffer);828HAS_INPUT(InBuffer);829830/* special code for 'Exec' */831if ( ExecRunning )832{833DEBUG( D_COMM, ("GapOutput: exec still active\n") );834len = 0;835while ( HAS_BUFFERED(InBuffer) && len < SIZE_BUFFER-3 )836{837/* '@' is special */838if ( CURRENT(InBuffer) == '@' )839{840(void) READ_CURRENT(InBuffer);841WaitInput(&InBuffer);842if ( CURRENT(InBuffer) == 'm' )843{844845/* get ride of any output left over */846if ( 0 < len )847{848TBuf[len] = 0;849GTReplaceText( GapTalk, TBuf, len );850if ( SpyMode )851fwrite( TBuf, 1, len, stderr );852}853854/* collect ouptut 'TBuf' in case it is not "mAgIc" */855len = 0;856TBuf[len++] = '@';857TBuf[len++] = 'm';858(void)READ_CURRENT(InBuffer);859WaitInput(&InBuffer);860if ( CURRENT(InBuffer) != 'A' ) continue;861(void)READ_CURRENT(InBuffer);862TBuf[len++] = 'A';863WaitInput(&InBuffer);864if ( CURRENT(InBuffer) != 'g' ) continue;865(void)READ_CURRENT(InBuffer);866TBuf[len++] = 'g';867WaitInput(&InBuffer);868if ( CURRENT(InBuffer) != 'I' ) continue;869(void)READ_CURRENT(InBuffer);870TBuf[len++] = 'I';871WaitInput(&InBuffer);872if ( CURRENT(InBuffer) != 'c' ) continue;873(void)READ_CURRENT(InBuffer);874len = 0;875ExecRunning = False;876DEBUG( D_COMM, ("GapOutput: %s: '%s'\n",877"leaving exec loop, input remaining",878InBuffer.buffer+InBuffer.pos) );879goto end_exec_loop;880881}882else883{884TBuf[len++] = '@';885continue;886}887}888889/* store input */890else891TBuf[len++] = READ_CURRENT(InBuffer);892}893TBuf[len] = 0;894GTReplaceText( GapTalk, TBuf, len );895if ( SpyMode )896fwrite( TBuf, 1, len, stderr );897return;898}899end_exec_loop:900901/* process gap output */902while ( HAS_BUFFERED(InBuffer) )903{904/* '@' is special */905if ( CURRENT(InBuffer) == '@' )906{907(void) READ_CURRENT(InBuffer);908WaitInput(&InBuffer);909if ( 'A' <= CURRENT(InBuffer) && CURRENT(InBuffer) <= 'Z' )910{911special = 0;912ch = READ_CURRENT(InBuffer);913ch = CTR(ch);914}915else if ( CURRENT(InBuffer) == '@' )916{917special = 0;918ch = READ_CURRENT(InBuffer);919}920else if ( CURRENT(InBuffer) == 'z' )921{922(void)READ_CURRENT(InBuffer);923ExecRunning = True;924DEBUG( D_COMM, ("GapOutput: entering exec loop\n") );925GapOutput( cld, fid, id );926return;927}928929else930{931special = 1;932ch = READ_CURRENT(InBuffer);933}934}935else936{937special = 0;938ch = READ_CURRENT(InBuffer);939}940941/* process window commands */942if ( special )943{944945/* '1' to '6' are garbage */946if ( '1' <= ch && ch <= '6' )947{948Int size;949ParseInt( &InBuffer, &size );950UpdateMemoryInfo( (int) (ch-'0'), size );951}952953/* '!','"','#','$','%','&' are garbage */954else if ( '!' <= ch && ch <= '&' ) {955Int size;956ParseInt( &InBuffer, &size );957}958959/* 'i' means gap is waiting for input */960else if ( ch == 'i' )961{962LastLine = GTPosition(GapTalk);963GapState = GAP_INPUT;964UpdateMenus(GapState);965UpdateXCMDS(True);966ProcessStoredInput(0);967}968969/* 'e' means gap is waiting for error input */970else if ( ch == 'e' )971{972LastLine = GTPosition(GapTalk);973GapState = GAP_ERROR;974UpdateMenus(GapState);975UpdateXCMDS(True);976ProcessStoredInput(0);977}978979/* 'r' is the current input line */980else if ( ch == 'r' )981{982ReadLine(&InBuffer);983GTSetPosition( GapTalk, LastLine );984GTReplaceText( GapTalk, GapBuffer, strlen(GapBuffer) );985if ( SpyMode )986{987fwrite( GapBuffer, 1, strlen(GapBuffer), stderr );988}989GapState = GAP_RUNNING;990UpdateMenus(GapState);991UpdateXCMDS(False);992ProcessStoredInput(1);993LastLine = -1;994}995996/* 'x' no text at current line */997else if ( ch == 'x' )998{999GTSetPosition( GapTalk, LastLine );1000GTReplaceText( GapTalk, "", 0 );1001GapState = GAP_RUNNING;1002UpdateMenus(GapState);1003UpdateXCMDS(True);1004LastLine = -1;1005}10061007/* 'c' completion output started */1008else if ( ch == 'c' )1009{1010GapState = GAP_RUNNING;1011UpdateMenus(GapState);1012UpdateXCMDS(True);1013LastLine = -1;1014}10151016/* 'h' help output started */1017else if ( ch == 'h' )1018{1019GapState = GAP_HELP;1020UpdateMenus(GapState);1021UpdateXCMDS(False);1022LastLine = -1;1023}10241025/* 'w' is a window command */1026else if ( ch == 'w' )1027{1028long i;1029long m;1030char * ptr;1031char * cmd;10321033len = 0;1034WaitInput(&InBuffer);1035ch = READ_CURRENT(InBuffer);1036for ( len = 0, m = 1; '0' <= ch && ch <= '9'; m *= 10 ) {1037len += (ch-'0') * m;1038WaitInput(&InBuffer);1039ch = READ_CURRENT(InBuffer);1040}1041ptr = cmd = XtMalloc(len+1);1042i = len;1043while ( 0 < i )1044{1045WaitInput(&InBuffer);1046while ( HAS_INPUT(InBuffer) && 0 < i )1047{1048*ptr++ = READ_CURRENT(InBuffer);1049i--;1050}1051}1052*ptr++ = 0;1053GapWindowCmd( cmd, len );1054XtFree(cmd);1055}10561057/* ignore 'n' for the moment */1058else if ( ch == 'n' )1059ch = 'n';10601061/* ignore 'f' for the moment */1062else if ( ch == 'f' )1063ch = 'f';10641065/* ignore 's', see 'SimulateInput' */1066else if ( ch == 's' ) {1067WaitInput(&InBuffer);1068(void)READ_CURRENT(InBuffer);1069continue;1070}1071}10721073/* collect normal characters and display them */1074else if ( ' ' <= ch && ch < 127 && GapState == GAP_RUNNING )1075{1076TBuf[0] = ch;1077for ( len = 1; len<SIZE_BUFFER && HAS_BUFFERED(InBuffer); )1078if ( CURRENT(InBuffer) == '@' )1079{1080if ( LOOK_AHEAD(InBuffer) == 'n' )1081{1082(void)READ_CURRENT(InBuffer);1083/* WaitInput(&InBuffer); */1084(void)READ_CURRENT(InBuffer);1085}1086else if ( LOOK_AHEAD(InBuffer) == 'f' )1087{1088(void)READ_CURRENT(InBuffer);1089/* WaitInput(&InBuffer); */1090(void)READ_CURRENT(InBuffer);1091}1092else if ( LOOK_AHEAD(InBuffer) == 'J' )1093{1094(void)READ_CURRENT(InBuffer);1095/* WaitInput(&InBuffer); */1096(void)READ_CURRENT(InBuffer);1097TBuf[len++] = '\n';1098}1099else1100break;1101}1102else if ( ' '<=CURRENT(InBuffer) && CURRENT(InBuffer)<127 )1103TBuf[len++] = READ_CURRENT(InBuffer);1104else1105break;1106GTReplaceText( GapTalk, TBuf, len );1107}11081109/* collect normal characters and display them */1110else if ( ' ' <= ch && ch < 127 && GapState != GAP_RUNNING )1111{1112TBuf[0] = ch;1113for ( len = 1; len<SIZE_BUFFER && HAS_INPUT(InBuffer); len++ )1114if ( CURRENT(InBuffer) == '@' )1115break;1116else if ( ' '<=CURRENT(InBuffer) && CURRENT(InBuffer)<127 )1117TBuf[len] = READ_CURRENT(InBuffer);1118else1119break;1120GTReplaceText( GapTalk, TBuf, len );1121}11221123/* carriage return */1124else if ( ch == '\n' )1125{1126if ( GapState != GAP_INPUT && GapState != GAP_ERROR )1127GTReplaceText( GapTalk, &ch, 1 );1128}11291130/* <CTR-G> rings a bell */1131else if ( ch == CTR('G') )1132GTBell(GapTalk);11331134/* <CTR-H> moves to the left */1135else if ( ch == CTR('H') )1136GTMoveCaret( GapTalk, -1 );11371138/* ignore anything else */1139else1140ch = ch;1141}1142}114311441145/****************************************************************************1146**11471148*F * * * * * * * * * * * * starting/stopping gap + * * * * * * * * * * * * *1149*/115011511152/****************************************************************************1153**11541155*F KillGap() . . . . . . . . . . . . . . . . . . . . . kill the running gap1156*/1157void KillGap ()1158{1159if ( GapPID != -1 )1160{1161close(ToGap);1162kill( GapPID, SIGKILL );1163}1164}116511661167/****************************************************************************1168**1169*F InterruptGap() . . . . . . . . . . . . . . . . interupt the running gap1170*/1171void InterruptGap ()1172{1173if ( GapPID != -1 )1174kill( GapPID, SIGINT );1175}117611771178/****************************************************************************1179**1180*F GetMasterPty( <fid> ) . . . . . . . . . open a master pty (from "xterm")1181*/1182static String ptydev = 0;1183static String ttydev = 0;11841185#ifndef SYS_PTYDEV1186# ifdef hpux1187# define SYS_PTYDEV "/dev/ptym/ptyxx"1188# else1189# define SYS_PTYDEV "/dev/ptyxx"1190# endif1191#endif11921193#ifndef SYS_TTYDEV1194# ifdef hpux1195# define SYS_TTYDEV "/dev/pty/ttyxx"1196# else1197# define SYS_TTYDEV "/dev/ttyxx"1198# endif1199#endif12001201#ifndef SYS_PTYCHAR11202# ifdef hpux1203# define SYS_PTYCHAR1 "zyxwvutsrqp"1204# else1205# define SYS_PTYCHAR1 "pqrstuvwxyz"1206# endif1207#endif12081209#ifndef SYS_PTYCHAR21210# ifdef hpux1211# define SYS_PTYCHAR2 "fedcba9876543210"1212# else1213# define SYS_PTYCHAR2 "0123456789abcdef"1214# endif1215#endif121612171218static Boolean GetMasterPty ( pty )1219int * pty;1220{1221#if HAVE_GETPT && HAVE_PTSNAME_R1222if ((*pty = getpt()) > 0 )1223{1224if (grantpt(*pty) || unlockpt(*pty))1225return True;1226ptsname_r(*pty, ttydev, 80);1227return False;1228}1229return True;1230#else1231# ifdef att1232if ( (*pty = open( "/dev/ptmx", O_RDWR )) < 0 )1233return True;1234return False;12351236# else1237# ifdef __CYGWIN__1238static int slave = 0;12391240sprintf(ptydev, "/dev/ptmx");1241if ( (*pty = open( ptydev, O_RDWR )) >= 0 ) {1242/* O_NONBLOCK | O_NOCTTY */1243strcpy(ttydev, ptsname(*pty));1244revoke(ttydev); /* ???? NECESSARY ???? */1245return False;1246}1247errno = ENOENT; /* out of ptys */1248perror(" Failed on open CYGWIN pty");1249return True;1250# else1251# if HAVE_GETPSEUDOTTY1252return (*pty = getpseudotty( &ttydev, &ptydev )) >= 0 ? False : True;12531254# else1255# if HAVE__GETPTY1256char * line;12571258line = _getpty(pty, O_RDWR|O_NDELAY, 0600, 0) ;1259if (0 == line)1260return True;1261strcpy( ttydev, line );1262return False;12631264# else1265# if defined(sgi) || (defined(umips) && defined(USG))1266struct stat fstat_buf;12671268*pty = open( "/dev/ptc", O_RDWR );1269if ( *pty < 0 || (fstat (*pty, &fstat_buf)) < 0 )1270return True;1271sprintf( ttydev, "/dev/ttyq%d", minor(fstat_buf.st_rdev) );1272# if !defined(sgi)1273sprintf( ptydev, "/dev/ptyq%d", minor(fstat_buf.st_rdev) );1274if ( (*tty = open (ttydev, O_RDWR)) < 0 )1275{1276close (*pty);1277return True;1278}1279# endif1280return False;12811282# else1283static int devindex = 0;1284static int letter = 0;1285static int slave = 0;12861287while ( SYS_PTYCHAR1[letter] )1288{1289ttydev[strlen(ttydev)-2] = SYS_PTYCHAR1[letter];1290ptydev[strlen(ptydev)-2] = SYS_PTYCHAR1[letter];12911292while ( SYS_PTYCHAR2[devindex] )1293{1294ttydev[strlen(ttydev)-1] = SYS_PTYCHAR2[devindex];1295ptydev[strlen(ptydev)-1] = SYS_PTYCHAR2[devindex];12961297if ( (*pty = open( ptydev, O_RDWR )) >= 0 )1298if ( (slave = open( ttydev, O_RDWR, 0 )) >= 0 )1299{1300close(slave);1301(void) devindex++;1302return False;1303}1304devindex++;1305}1306devindex = 0;1307(void) letter++;1308}1309return True;1310# endif1311# endif1312# endif1313# endif1314# endif1315#endif1316}131713181319/****************************************************************************1320**1321*F StartGapProcess( <name>, <argv> ) . . . start a gap subprocess using ptys1322*/1323static void GapStatusHasChanged ()1324{1325# ifdef SYS_HAS_UNION_WAIT1326union wait w;1327# else1328int w;1329# endif13301331/* if the child was stopped return */1332if ( wait3( &w, WNOHANG | WUNTRACED, 0 ) != GapPID || WIFSTOPPED(w) )1333return;1334# ifdef DEBUG_ON1335fputs( "gap status has changed, leaving xgap\n", stderr );1336fprintf( stderr,"Signal: %d\n",WTERMSIG(w));1337# endif1338exit(1);1339}13401341int StartGapProcess ( name, argv )1342String name;1343String argv[];1344{1345Int j; /* loop variables */1346char c[8]; /* buffer for communication */1347int master; /* pipe to GAP */1348int n; /* return value of 'select' */1349int slave; /* pipe from GAP */1350/* struct */ fd_set fds; /* for 'select' */1351struct timeval timeout; /* time to wait for aknowledgement */13521353# if HAVE_TERMIOS_H1354struct termios tst; /* old and new terminal state */1355# else1356# if HAVE_TERMIO_H1357struct termio tst; /* old and new terminal state */1358# else1359struct sgttyb tst; /* old and new terminal state */1360# endif1361# endif13621363/* construct the name of the pseudo terminal */1364/* was:1365ttydev = XtMalloc(strlen(SYS_TTYDEV)+1); strcpy( ttydev, SYS_TTYDEV );1366ptydev = XtMalloc(strlen(SYS_PTYDEV)+1); strcpy( ptydev, SYS_PTYDEV );1367changed by Max 2.5.2004 because this might be too short! */1368ttydev = XtMalloc(81); strcpy( ttydev, SYS_TTYDEV );1369ptydev = XtMalloc(81); strcpy( ptydev, SYS_PTYDEV );13701371/* open pseudo terminal for communication with gap */1372if ( GetMasterPty(&master) )1373{1374fputs( "open master failed\n", stderr );1375exit(1);1376}1377if ( (slave = open( ttydev, O_RDWR, 0 )) < 0 )1378{1379fputs( "open slave failed\n", stderr );1380exit(1);1381}1382# if defined(DEBUG_ON) && !defined(att)1383DEBUG( D_COMM, ("StartGapProcess: master='%s', slave='%s'\n",1384ptydev ? ptydev : "unknown",1385ttydev ? ttydev : "unkown") );1386# endif1387# if HAVE_TERMIOS_H1388if ( tcgetattr( slave, &tst ) == -1 )1389{1390fputs( "tcgetattr on slave pty failed\n", stderr );1391exit(1);1392}1393tst.c_cc[VINTR] = 0377;1394tst.c_cc[VQUIT] = 0377;1395tst.c_iflag &= ~(INLCR|ICRNL);1396tst.c_cc[VMIN] = 1;1397tst.c_cc[VTIME] = 0;1398tst.c_lflag &= ~(ECHO|ICANON);1399if ( tcsetattr( slave, TCSANOW, &tst ) == -1 )1400{1401fputs( "tcsetattr on slave pty failed\n", stderr );1402exit(1);1403}1404# else1405# if HAVE_TERMIO_H1406if ( ioctl( slave, TCGETA, &tst ) == -1 )1407{1408fputs( "ioctl TCGETA on slave pty failed\n", stderr );1409exit(1);1410}1411tst.c_cc[VINTR] = 0377;1412tst.c_cc[VQUIT] = 0377;1413tst.c_iflag &= ~(INLCR|ICRNL);1414tst.c_cc[VMIN] = 1;1415tst.c_cc[VTIME] = 0;1416/* Note that this is at least on Linux dangerous!1417Therefore, we now have the HAVE_TERMIOS_H section for POSIX1418Terminal control. */1419tst.c_lflag &= ~(ECHO|ICANON);1420if ( ioctl( slave, TCSETAW, &tst ) == -1 )1421{1422fputs( "ioctl TCSETAW on slave pty failed\n", stderr );1423exit(1);1424}1425# else1426if ( ioctl( slave, TIOCGETP, (char*)&tst ) == -1 )1427{1428if ( ttydev )1429fprintf( stderr, "ioctl TIOCGETP on slave pty failed (%s)\n",1430ttydev );1431else1432fputs( "ioctl TIOCGETP on slave pty failed\n", stderr );1433exit(1);1434}1435tst.sg_flags |= RAW;1436tst.sg_flags &= ~ECHO;1437if ( ioctl( slave, TIOCSETN, (char*)&tst ) == -1 )1438{1439fputs( "ioctl on TIOCSETN slave pty failed\n", stderr );1440exit(1);1441}1442#endif1443#endif14441445/* set input to non blocking operation */1446if ( fcntl( master, F_SETFL, O_NDELAY ) < 0 )1447{1448fputs( "Panic: cannot set non blocking operation.\n", stderr );1449exit(1);1450}14511452/* fork to gap, dup pipe to stdin and stdout */1453GapPID = fork();1454if ( GapPID == 0 )1455{1456dup2( slave, 0 );1457dup2( slave, 1 );1458/* The following is necessary because otherwise the GAP process1459will ignore the SIGINT signal: */1460signal( SIGINT, SIG_DFL );1461# ifdef SYS_HAS_EXECV_CCHARPP1462execv( name, (const char**) argv );1463# else1464execv( name, (void*) argv );1465# endif1466if (write( 1, "@-", 2) < 2) fputs("Child: Cannot write @-", stderr);1467close(slave);1468_exit(1);1469}1470ToGap = master;1471FromGap = master;14721473/* check if the fork was successful */1474if ( GapPID == -1 )1475{1476fputs( "Panic: cannot fork to subprocess.\n", stderr );1477exit(1);1478}14791480/* wait at least 60 sec before giving up */1481timeout.tv_sec = 60;1482timeout.tv_usec = 0;14831484/* wait for an aknowledgement (@p) from the gap subprocess */1485j = 0;1486while ( j < 10 && c[j-1] != '.' )1487{14881489/* set <FromGap> port for listen */1490# ifdef FD_SET1491FD_ZERO(&fds);1492FD_SET( FromGap, &fds );1493# else1494{1495Int i;14961497for ( i = FromGap/sizeof(fds.fds_bits); 0 <= i; i-- )1498fds.fds_bits[i] = 0;1499fds.fds_bits[FromGap/sizeof(fds.fds_bits)] =1500( 1 << (FromGap % sizeof(fds.fds_bits)) );1501}1502# endif15031504/* use 'select' to check port */1505if ( (n = select(FromGap+1, &fds, 0, 0, &timeout)) == -1 )1506{1507kill( GapPID, SIGKILL );1508perror("select failed");1509exit(1);1510}1511else if ( n == 0 )1512{1513kill( GapPID, SIGKILL );1514fputs("Panic: cannot establish communication with gap.", stderr);1515exit(1);1516}1517else1518ReadGap( &(c[j++]), 1 );1519}15201521/* check if we got "@p" */1522if ( c[j-1] != '.' || strncmp( c, "@p", 2 ) )1523{1524if ( ! strncmp( c, "@-", 2 ) )1525{1526fputs( "Panic: cannot start subprocess ", stderr );1527fputs( name, stderr );1528fputs( ".\n", stderr );1529}1530else1531{1532strcpy( c+3, "'\n" );1533fputs( "Panic: cannot talk with gap, got '", stderr );1534fputs( c, stderr );1535kill( GapPID, SIGKILL );1536}1537exit(1);1538}15391540/* if the gap dies, stop program */1541signal( SIGCHLD, GapStatusHasChanged );1542InBuffer.pos = InBuffer.len = 0;1543return FromGap;1544}154515461547/****************************************************************************1548**15491550*E pty.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ends here1551*/155215531554