Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download

GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it

610987 views
1
/****************************************************************************
2
**
3
*W pty.c XGAP source Frank Celler
4
**
5
**
6
*Y Copyright 1995-1997, Lehrstuhl D fuer Mathematik, RWTH Aachen, Germany
7
*Y Copyright 1997, Frank Celler, Huerth, Germany
8
**
9
** This file contains all the code for handling pseudo ttys. 'GetMasterPty'
10
** is based on code from 'xterm'.
11
**
12
** GAP is started in a special mode that will mask special characters. The
13
** following '@' sequences produced by GAP are recoginzed:
14
**
15
** 'pX.' package mode version X
16
** '@' a single '@'
17
** 'A'..'Z' a control character
18
** '1','2','3','4','5','6' full garbage collection information
19
** '!','"','#','$','%','&' partial garbage collection information
20
** 'e' gap is waiting for error input
21
** 'c' completion started
22
** 'f' error output
23
** 'h' help started
24
** 'i' gap is waiting for input
25
** 'm' end of 'Exec'
26
** 'n' normal output
27
** 'r' the current input line follows
28
** 'sN' ACK for '@yN'
29
** 'w' a window command follows
30
** 'x' the current input line is empty
31
** 'z' start of 'Exec'
32
*/
33
#include "utils.h"
34
35
#include "gaptext.h"
36
#include "xcmds.h"
37
#include "xgap.h"
38
39
#include "pty.h"
40
41
42
/****************************************************************************
43
**
44
45
*F * * * * * * * * * * * * * * local variables * * * * * * * * * * * * * * *
46
*/
47
48
49
/****************************************************************************
50
**
51
52
*V GapPID . . . . . . . . . . . . . . . . . . . . . . . . gap subprocess id
53
*/
54
static int GapPID = -1;
55
56
57
/****************************************************************************
58
**
59
*V FromGap . . . . . . . . . . . . . . . . . . . . . . for messages from gap
60
*/
61
static int FromGap;
62
63
64
/****************************************************************************
65
**
66
*V ToGap . . . . . . . . . . . . . . . . . . . . . . . . for messages to gap
67
*/
68
static int ToGap;
69
70
71
/* * * * * * * * * * * * * * global variables * * * * * * * * * * * * * * */
72
73
74
/****************************************************************************
75
**
76
77
*V QuitGapCtrlD . . . . . . . . . . . . . . . . . . . . . . . quit on CTR-D
78
*/
79
Boolean QuitGapCtrlD = FALSE;
80
81
82
/****************************************************************************
83
**
84
*V ScreenSizeBuffer . . . . . . . . . . . . . . screen size change command
85
*/
86
char ScreenSizeBuffer[1024] = { 0 };
87
88
89
/****************************************************************************
90
**
91
*V ExecRunning . . . . . . . . . . . . . . . . . . external program running
92
*/
93
Boolean ExecRunning = False;
94
95
96
/****************************************************************************
97
**
98
99
*F * * * * * * * * * * * * communication with GAP * * * * * * * * * * * * *
100
*/
101
102
103
/****************************************************************************
104
**
105
106
*F ReadGap( <line>, <len> ) . . . . . . . . . . . . . . . . read gap output
107
*/
108
#ifdef DEBUG_ON
109
110
Int READ_GAP ( file, where, line, len )
111
String file;
112
Int where;
113
String line;
114
Int len;
115
{
116
Int n;
117
Int old;
118
119
if ( Debug & D_COMM )
120
{
121
printf( "%04d:%s: ReadGap( buf, %d ) = ", where, file, len );
122
fflush( stdout );
123
}
124
if ( len < 0 )
125
{
126
len = read( FromGap, line, -len );
127
if ( Debug & D_COMM )
128
{
129
if ( len == -1 )
130
fprintf( stdout, "-1: no input\n" );
131
else
132
{
133
fprintf( stdout, "%d: '", len );
134
fwrite( line, 1, len, stdout );
135
fprintf( stdout, "'\n" );
136
}
137
fflush( stdout );
138
}
139
return len;
140
}
141
else
142
{
143
old = len;
144
while ( 0 < len )
145
{
146
while ( ( n = read( FromGap, line, len ) ) < 0 )
147
;
148
line = line + n;
149
len = len - n;
150
}
151
if ( Debug & D_COMM )
152
{
153
fprintf( stdout, "%d: '", old );
154
fwrite( line-old, 1, old, stdout );
155
fprintf( stdout, "'\n" );
156
fflush( stdout );
157
}
158
return old;
159
}
160
}
161
162
#else
163
164
Int ReadGap ( line, len )
165
String line;
166
Int len;
167
{
168
Int n;
169
Int old;
170
171
if ( len < 0 )
172
return read( FromGap, line, -len );
173
else
174
{
175
old = len;
176
while ( 0 < len )
177
{
178
while ( ( n = read( FromGap, line, len ) ) < 0 )
179
;
180
line = line + n;
181
len = len - n;
182
}
183
return old;
184
}
185
}
186
187
#endif
188
189
190
/****************************************************************************
191
**
192
*F WriteGap( <line>, <len> ) . . . . . . . . . . . . . . . . write gap input
193
*/
194
extern int errno;
195
196
#ifdef DEBUG_ON
197
198
void WRITE_GAP ( file, where, line, len )
199
String file;
200
Int where;
201
String line;
202
Int len;
203
{
204
Int res;
205
206
if ( Debug & D_COMM )
207
{
208
printf( "%04d:%s: WriteGap( %d ) = '", where, file, len );
209
fwrite( line, 1, len, stdout );
210
fprintf( stdout, "'\n" );
211
fflush( stdout );
212
}
213
while ( 0 < len )
214
{
215
res = write( ToGap, line, len );
216
if ( res < 0 )
217
{
218
if ( errno == EAGAIN )
219
continue;
220
perror( "WriteGap" );
221
KillGap();
222
exit(1);
223
}
224
len -= res;
225
line += res;
226
}
227
}
228
229
#else
230
231
void WriteGap ( line, len )
232
String line;
233
Int len;
234
{
235
Int res;
236
237
while ( 0 < len )
238
{
239
res = write( ToGap, line, len );
240
if ( res < 0 )
241
{
242
if ( errno == EAGAIN )
243
continue;
244
perror( "WriteGap" );
245
KillGap();
246
exit(1);
247
}
248
len -= res;
249
line += res;
250
}
251
}
252
253
#endif
254
255
256
/****************************************************************************
257
**
258
259
*V InBuffer . . . . . . . . . . . . . . . . . . . . . buffer of gap output
260
*/
261
#define SIZE_BUFFER 16000
262
263
static struct _in_buf
264
{
265
char buffer[SIZE_BUFFER];
266
Int pos;
267
Int len;
268
}
269
InBuffer;
270
271
272
/****************************************************************************
273
**
274
*V GapBuffer . . . . . . . . . . . . . . . . temporary buffer for 'ReadLine'
275
*/
276
static char GapBuffer[SIZE_BUFFER];
277
278
279
/****************************************************************************
280
**
281
*V LastLine . . . . . . . . . . . . . . . . . . . . beginning of last line
282
*/
283
static Int LastLine;
284
285
286
/****************************************************************************
287
**
288
289
*D CURRENT( <buf> ) . . . . . . . . . . . . . . . . . . . . current symbol
290
*/
291
#define CURRENT(buf) ((buf).buffer[(buf).pos])
292
293
294
/****************************************************************************
295
**
296
*D READ_CURRENT( <buf> ) . . . . . . . . . . . . . . consume current symbol
297
*/
298
#define READ_CURRENT(buf) ((buf).buffer[(buf).pos++])
299
300
301
/****************************************************************************
302
**
303
*D HAS_INPUT( <buf> ) . . . . . . . . . . . . . . . . . . . check for input
304
*/
305
#define HAS_INPUT(buf) ( ((buf).len <= (buf).pos) ? (buf).pos = 0, \
306
((buf).len=ReadGap((buf).buffer,-SIZE_BUFFER))>0 :\
307
1 )
308
309
310
/****************************************************************************
311
**
312
*D HAS_BUFFERED( <buf> ) . . . . . . . . . . . . . check for buffered input
313
*/
314
#define HAS_BUFFERED(buf) ( (buf).pos < (buf).len )
315
316
317
/****************************************************************************
318
**
319
*D LOOK_AHEAD( <buf> ) . . . look ahead if there is enough input, dont check
320
*/
321
#define LOOK_AHEAD(buf) ( ((buf).pos+1 < (buf).len ) ? \
322
((buf).buffer)[(buf).pos+1] : '\0' )
323
324
325
/****************************************************************************
326
**
327
328
*F WaitInput( <buf> ) . . . . . . . . . . . . . . . wait for one character
329
*/
330
void WaitInput ( buf )
331
struct _in_buf * buf;
332
{
333
Int len;
334
335
if ( buf->len <= buf->pos )
336
{
337
buf->pos = 0;
338
ReadGap( buf->buffer, 1 );
339
len = ReadGap( buf->buffer+1, -(SIZE_BUFFER-1) );
340
buf->len = (len < 0) ? 1 : len+1;
341
}
342
}
343
344
345
/****************************************************************************
346
**
347
*F WaitInput2( <buf> ) . . . . . . . . . . . . . . . wait for two characters
348
*/
349
void WaitInput2 ( buf )
350
struct _in_buf * buf;
351
{
352
Int len;
353
354
if ( buf->len <= 1 + buf->pos )
355
{
356
if ( buf->pos+1 == buf->len )
357
{
358
*buf->buffer = buf->buffer[buf->pos];
359
buf->pos = 0;
360
ReadGap( buf->buffer+1, 1 );
361
len = ReadGap( buf->buffer+2, -(SIZE_BUFFER-2) );
362
buf->len = (len < 0) ? 2 : len+2;
363
}
364
else
365
{
366
buf->pos = 0;
367
ReadGap( buf->buffer, 2 );
368
len = ReadGap( buf->buffer+2, -(SIZE_BUFFER-2) );
369
buf->len = (len < 0) ? 2 : len+2;
370
}
371
}
372
}
373
374
/****************************************************************************
375
**
376
*F ReadLine( <buf> ) . . . . . . . . . . . . . . . . . . . . . . read a line
377
*/
378
void ReadLine ( buf )
379
struct _in_buf * buf;
380
{
381
String ptr = GapBuffer;
382
383
do
384
{
385
WaitInput(buf);
386
if ( CURRENT(*buf) == '\n' )
387
{
388
*ptr++ = READ_CURRENT(*buf);
389
*ptr = 0;
390
return;
391
}
392
else if ( CURRENT(*buf) == '\r' )
393
(void) READ_CURRENT(*buf);
394
else if ( CURRENT(*buf) == '@' )
395
{
396
(void) READ_CURRENT(*buf);
397
WaitInput(buf);
398
if ( CURRENT(*buf) == 'J' )
399
{
400
*ptr++ = '\n';
401
*ptr = 0;
402
(void) READ_CURRENT(*buf);
403
return;
404
}
405
else if ( CURRENT(*buf) != '@' )
406
*ptr++ = '^';
407
*ptr++ = READ_CURRENT(*buf);
408
}
409
else
410
*ptr++ = READ_CURRENT(*buf);
411
} while ( 1 );
412
}
413
414
415
/****************************************************************************
416
**
417
418
*F StoreInput( <str>, <len> ) . . . . . . . . . store input for later usage
419
*/
420
static struct _storage
421
{
422
String buffer;
423
Int size;
424
Int len;
425
}
426
Storage = { 0, 0, 0 };
427
428
void StoreInput ( str, len )
429
String str;
430
Int len;
431
{
432
if ( Storage.buffer == 0 )
433
{
434
Storage.buffer = XtMalloc(4096);
435
Storage.size = 4096;
436
}
437
if ( Storage.size <= Storage.len + len )
438
{
439
Storage.size += ((len/4096+1) * 4096);
440
Storage.buffer = XtRealloc( Storage.buffer, Storage.size );
441
}
442
memcpy( Storage.buffer+Storage.len, str, len );
443
Storage.len += len;
444
}
445
446
447
/****************************************************************************
448
**
449
*F ProcessStoredInput( <state> ) . . . . . . . . . feed stored input to gap
450
*/
451
static Char InputCookie = 'A';
452
453
void ProcessStoredInput ( state )
454
Int state;
455
{
456
String ptr;
457
String free;
458
Int len;
459
static Boolean inProgress = False;
460
461
/* if we are already processing input do not start again */
462
if ( inProgress || state != 0 )
463
return;
464
465
/* if gap is not accepting input return */
466
if ( GapState != GAP_INPUT && GapState != GAP_ERROR )
467
return;
468
469
/* if no input is waiting return */
470
if ( Storage.len == 0 && *ScreenSizeBuffer == 0 )
471
return;
472
473
/* otherwise make sure that gap does not want to tell use something */
474
again:
475
if ( HAS_INPUT(InBuffer) )
476
GapOutput( 0, 0, 0 );
477
if ( GapState != GAP_INPUT && GapState != GAP_ERROR )
478
return;
479
480
/* send '@yN' and wait for ACK '@sN' */
481
if ( InputCookie++ == 'Z' ) InputCookie = 'A';
482
WriteGap( "@y", 2 );
483
WriteGap( &InputCookie, 1 );
484
WaitInput(&InBuffer);
485
if ( CURRENT(InBuffer) != '@' )
486
goto again;
487
WaitInput2(&InBuffer);
488
if ( LOOK_AHEAD(InBuffer) != 's' )
489
goto again;
490
(void)READ_CURRENT(InBuffer);
491
(void)READ_CURRENT(InBuffer);
492
WaitInput(&InBuffer);
493
if ( READ_CURRENT(InBuffer) != InputCookie )
494
goto again;
495
496
/* if the screen was resized, process resize command first */
497
if ( *ScreenSizeBuffer != 0 )
498
{
499
WriteGap( ScreenSizeBuffer, strlen(ScreenSizeBuffer) );
500
*ScreenSizeBuffer = 0;
501
return;
502
}
503
504
/* start processing input, check reaction of gap */
505
inProgress = True;
506
len = Storage.len;
507
free = ptr = Storage.buffer;
508
while ( 0 < len )
509
{
510
WriteGap( ptr, 1 ); len--; ptr++;
511
if ( ptr[-1] == '\n'
512
|| ptr[-1] == '\r'
513
|| (free<ptr-1 && ptr[-2]=='@' && ptr[-1]=='M')
514
|| (free<ptr-1 && ptr[-2]=='@' && ptr[-1]=='J')
515
)
516
break;
517
if ( ! QuitGapCtrlD && GapState == GAP_INPUT
518
&& ptr[-1] == '@' && ptr[0] == 'D' )
519
{
520
WriteGap( "F@H", 3 );
521
len--;
522
ptr++;
523
}
524
}
525
526
/* create new buffer, store remaining input, and free old */
527
inProgress = False;
528
if ( len <= Storage.size )
529
{
530
Storage.len = len;
531
for ( ; 0 < len; len-- )
532
*free++ = *ptr++;
533
}
534
else
535
{
536
Storage.size = ( 4096 < len ) ? len : 4096;
537
Storage.buffer = XtMalloc(Storage.size);
538
memcpy( Storage.buffer, ptr, len );
539
Storage.len = len;
540
XtFree(free);
541
}
542
if ( GapState == GAP_HELP )
543
ProcessStoredInput(0);
544
}
545
546
547
/****************************************************************************
548
**
549
*F SimulateInput( <str> ) . . . . . . . . . . enter a line as command line
550
*/
551
void SimulateInput ( str )
552
String str;
553
{
554
Int pos;
555
556
/* if <GAP> is not accepting input, discard line */
557
if ( GapState != GAP_INPUT && GapState != GAP_ERROR )
558
return;
559
560
/* ok, do it. get current cursor position */
561
pos = GTPosition(GapTalk) - LastLine;
562
StoreInput( "@A@K", 4 );
563
StoreInput( str, strlen(str) );
564
StoreInput( "@Y@A", 4 );
565
while ( 0 < pos-- )
566
StoreInput( "@F", 2 );
567
ProcessStoredInput(0);
568
}
569
570
571
/****************************************************************************
572
**
573
*F KeyboardInput( <str>, <len> ) . . . . . . . . . . process keyboard input
574
*/
575
Boolean PlayingBack = False;
576
FILE * Playback = 0;
577
578
int PlaybackFile ( str )
579
String str;
580
{
581
if ( Playback != 0 ) {
582
fclose(Playback);
583
}
584
Playback = fopen( str, "r" );
585
if ( Playback != 0 ) {
586
PlayingBack = True;
587
}
588
else {
589
PlayingBack = False;
590
}
591
return PlayingBack;
592
}
593
594
int ResumePlayback ( void )
595
{
596
if ( PlayingBack || Playback == 0 )
597
return False;
598
PlayingBack = True;
599
return True;
600
}
601
602
void KeyboardInput ( str, len )
603
String str;
604
Int len;
605
{
606
char buf[1025];
607
608
#ifndef EXIT_ON_DOUBLE_CTR_C
609
static Int ltime = 0;
610
Int ntime;
611
#endif
612
613
/* read playback file */
614
if ( PlayingBack && GapState == GAP_INPUT ) {
615
if ( *str == 'q' || *str == 'Q' ) {
616
fclose(Playback);
617
PlayingBack = False;
618
Playback = 0;
619
StoreInput( "\"Playback STOPPED\";;\n", 21 );
620
}
621
else if ( *str=='z' || *str=='Z' || *str=='y' || *str=='Y' ) {
622
PlayingBack = False;
623
StoreInput( "\"Playback SUPENDED\";;\n", 22 );
624
}
625
else {
626
if ( fgets( buf, 1024, Playback ) == 0 ) {
627
fclose(Playback);
628
PlayingBack = False;
629
Playback = 0;
630
}
631
else {
632
StoreInput( buf, strlen(buf) );
633
if ( feof(Playback) ) {
634
fclose(Playback);
635
PlayingBack = False;
636
Playback = 0;
637
}
638
}
639
if ( ! PlayingBack )
640
StoreInput( "\"Playback ENDED\";;\n", 19 );
641
}
642
}
643
644
/* handle help mode directly */
645
else if ( GapState == GAP_HELP )
646
{
647
if ( HAS_INPUT(InBuffer) || HAS_INPUT(InBuffer) )
648
GapOutput( 0, 0, 0 );
649
if ( GapState != GAP_HELP )
650
{
651
KeyboardInput( str, len );
652
return;
653
}
654
655
/* send '@yN' and wait for ACK '@sN' */
656
if ( InputCookie++ == 'Z' ) InputCookie = 'A';
657
WriteGap( "@y", 2 );
658
WriteGap( &InputCookie, 1 );
659
WaitInput(&InBuffer);
660
if ( CURRENT(InBuffer) != '@' )
661
{
662
GapOutput( 0, 0, 0 );
663
KeyboardInput( str, len );
664
return;
665
}
666
WaitInput2(&InBuffer);
667
if ( LOOK_AHEAD(InBuffer) != 's' )
668
{
669
GapOutput( 0, 0, 0 );
670
KeyboardInput( str, len );
671
return;
672
}
673
(void)READ_CURRENT(InBuffer);
674
(void)READ_CURRENT(InBuffer);
675
if ( READ_CURRENT(InBuffer) != InputCookie ) {
676
GapOutput( 0, 0, 0 );
677
KeyboardInput( str, len );
678
return;
679
}
680
681
/* write a character and start again */
682
WriteGap( str, 1 );
683
if ( *str == '@' && 1 < len )
684
{
685
WriteGap( str+1, 1 );
686
str++;
687
len--;
688
}
689
str++;
690
len--;
691
if ( 0 < len )
692
KeyboardInput( str, len );
693
return;
694
}
695
696
/* consume input */
697
else if ( PlayingBack && GapState == GAP_RUNNING ) {
698
;
699
}
700
else {
701
while ( 0 < len )
702
{
703
704
/* handle <CTR-C> */
705
if ( 2 <= len && *str == '@' && str[1] == 'C' )
706
{
707
# ifndef EXIT_ON_DOUBLE_CTR_C
708
while ( 2 <= len && *str == '@' && str[1] == 'C' )
709
{
710
str += 2;
711
len -= 2;
712
}
713
ntime = (int) time(0);
714
if ( 2 < ntime - ltime )
715
InterruptGap();
716
ltime = ntime;
717
# else
718
InterruptGap();
719
str += 2;
720
len -= 2;
721
# endif
722
}
723
724
/* otherwise store it */
725
else
726
{
727
StoreInput( str, 1 );
728
len--;
729
str++;
730
}
731
}
732
}
733
734
/* try to process input */
735
ProcessStoredInput(0);
736
}
737
738
739
/****************************************************************************
740
**
741
*F CheckCaretPos( <new>, <old> ) . . . . . . . . . . . check caret movement
742
*/
743
Int CheckCaretPos ( new, old )
744
Int new;
745
Int old;
746
{
747
/* if <LastLine> is -1, then gap is running, ignore move */
748
if ( LastLine < 0 )
749
return 0;
750
751
/* if the new position is before the last line, ignore move */
752
else if ( new < LastLine )
753
return 0;
754
755
/* otherwise move in the correct direction */
756
else if ( new < old )
757
{
758
while ( new++ < old )
759
WriteGap( "@B", 2 );
760
return 0;
761
}
762
else if ( old < new )
763
{
764
while ( old++ < new )
765
WriteGap( "@F", 2 );
766
return 0;
767
}
768
else
769
return 0;
770
}
771
772
773
/****************************************************************************
774
**
775
*F ParseInt( <buf>, <val> ) . . . . . . . . . . . . . . . get a long value
776
*/
777
static Boolean ParseInt (
778
struct _in_buf * buf,
779
Int * val )
780
{
781
Int mult;
782
783
*val = 0;
784
mult = 1;
785
do
786
{
787
WaitInput(buf);
788
if ( CURRENT(*buf) == '+' )
789
{
790
(void) READ_CURRENT(*buf);
791
return True;
792
}
793
else if ( CURRENT(*buf) == '-' )
794
{
795
(void) READ_CURRENT(*buf);
796
*val = -*val;
797
return True;
798
}
799
else if ( '0' <= CURRENT(*buf) && CURRENT(*buf) <= '9' )
800
*val += mult * (READ_CURRENT(*buf)-'0');
801
else
802
return False;
803
mult = mult * 10;
804
} while (1);
805
}
806
807
808
/****************************************************************************
809
**
810
*F GapOutput( <cld>, <fid>, <id> ) . . . . . . . . . . . . handle gap output
811
*/
812
#undef CTR
813
#define CTR(a) ( a & 0x1f )
814
815
static char TBuf[SIZE_BUFFER];
816
817
void GapOutput ( cld, fid, id )
818
XtPointer cld;
819
int * fid;
820
XtInputId id;
821
{
822
char ch;
823
Int special;
824
Int len;
825
826
/* wait a while for input */
827
HAS_INPUT(InBuffer);
828
HAS_INPUT(InBuffer);
829
HAS_INPUT(InBuffer);
830
831
/* special code for 'Exec' */
832
if ( ExecRunning )
833
{
834
DEBUG( D_COMM, ("GapOutput: exec still active\n") );
835
len = 0;
836
while ( HAS_BUFFERED(InBuffer) && len < SIZE_BUFFER-3 )
837
{
838
/* '@' is special */
839
if ( CURRENT(InBuffer) == '@' )
840
{
841
(void) READ_CURRENT(InBuffer);
842
WaitInput(&InBuffer);
843
if ( CURRENT(InBuffer) == 'm' )
844
{
845
846
/* get ride of any output left over */
847
if ( 0 < len )
848
{
849
TBuf[len] = 0;
850
GTReplaceText( GapTalk, TBuf, len );
851
if ( SpyMode )
852
fwrite( TBuf, 1, len, stderr );
853
}
854
855
/* collect ouptut 'TBuf' in case it is not "mAgIc" */
856
len = 0;
857
TBuf[len++] = '@';
858
TBuf[len++] = 'm';
859
(void)READ_CURRENT(InBuffer);
860
WaitInput(&InBuffer);
861
if ( CURRENT(InBuffer) != 'A' ) continue;
862
(void)READ_CURRENT(InBuffer);
863
TBuf[len++] = 'A';
864
WaitInput(&InBuffer);
865
if ( CURRENT(InBuffer) != 'g' ) continue;
866
(void)READ_CURRENT(InBuffer);
867
TBuf[len++] = 'g';
868
WaitInput(&InBuffer);
869
if ( CURRENT(InBuffer) != 'I' ) continue;
870
(void)READ_CURRENT(InBuffer);
871
TBuf[len++] = 'I';
872
WaitInput(&InBuffer);
873
if ( CURRENT(InBuffer) != 'c' ) continue;
874
(void)READ_CURRENT(InBuffer);
875
len = 0;
876
ExecRunning = False;
877
DEBUG( D_COMM, ("GapOutput: %s: '%s'\n",
878
"leaving exec loop, input remaining",
879
InBuffer.buffer+InBuffer.pos) );
880
goto end_exec_loop;
881
882
}
883
else
884
{
885
TBuf[len++] = '@';
886
continue;
887
}
888
}
889
890
/* store input */
891
else
892
TBuf[len++] = READ_CURRENT(InBuffer);
893
}
894
TBuf[len] = 0;
895
GTReplaceText( GapTalk, TBuf, len );
896
if ( SpyMode )
897
fwrite( TBuf, 1, len, stderr );
898
return;
899
}
900
end_exec_loop:
901
902
/* process gap output */
903
while ( HAS_BUFFERED(InBuffer) )
904
{
905
/* '@' is special */
906
if ( CURRENT(InBuffer) == '@' )
907
{
908
(void) READ_CURRENT(InBuffer);
909
WaitInput(&InBuffer);
910
if ( 'A' <= CURRENT(InBuffer) && CURRENT(InBuffer) <= 'Z' )
911
{
912
special = 0;
913
ch = READ_CURRENT(InBuffer);
914
ch = CTR(ch);
915
}
916
else if ( CURRENT(InBuffer) == '@' )
917
{
918
special = 0;
919
ch = READ_CURRENT(InBuffer);
920
}
921
else if ( CURRENT(InBuffer) == 'z' )
922
{
923
(void)READ_CURRENT(InBuffer);
924
ExecRunning = True;
925
DEBUG( D_COMM, ("GapOutput: entering exec loop\n") );
926
GapOutput( cld, fid, id );
927
return;
928
}
929
930
else
931
{
932
special = 1;
933
ch = READ_CURRENT(InBuffer);
934
}
935
}
936
else
937
{
938
special = 0;
939
ch = READ_CURRENT(InBuffer);
940
}
941
942
/* process window commands */
943
if ( special )
944
{
945
946
/* '1' to '6' are garbage */
947
if ( '1' <= ch && ch <= '6' )
948
{
949
Int size;
950
ParseInt( &InBuffer, &size );
951
UpdateMemoryInfo( (int) (ch-'0'), size );
952
}
953
954
/* '!','"','#','$','%','&' are garbage */
955
else if ( '!' <= ch && ch <= '&' ) {
956
Int size;
957
ParseInt( &InBuffer, &size );
958
}
959
960
/* 'i' means gap is waiting for input */
961
else if ( ch == 'i' )
962
{
963
LastLine = GTPosition(GapTalk);
964
GapState = GAP_INPUT;
965
UpdateMenus(GapState);
966
UpdateXCMDS(True);
967
ProcessStoredInput(0);
968
}
969
970
/* 'e' means gap is waiting for error input */
971
else if ( ch == 'e' )
972
{
973
LastLine = GTPosition(GapTalk);
974
GapState = GAP_ERROR;
975
UpdateMenus(GapState);
976
UpdateXCMDS(True);
977
ProcessStoredInput(0);
978
}
979
980
/* 'r' is the current input line */
981
else if ( ch == 'r' )
982
{
983
ReadLine(&InBuffer);
984
GTSetPosition( GapTalk, LastLine );
985
GTReplaceText( GapTalk, GapBuffer, strlen(GapBuffer) );
986
if ( SpyMode )
987
{
988
fwrite( GapBuffer, 1, strlen(GapBuffer), stderr );
989
}
990
GapState = GAP_RUNNING;
991
UpdateMenus(GapState);
992
UpdateXCMDS(False);
993
ProcessStoredInput(1);
994
LastLine = -1;
995
}
996
997
/* 'x' no text at current line */
998
else if ( ch == 'x' )
999
{
1000
GTSetPosition( GapTalk, LastLine );
1001
GTReplaceText( GapTalk, "", 0 );
1002
GapState = GAP_RUNNING;
1003
UpdateMenus(GapState);
1004
UpdateXCMDS(True);
1005
LastLine = -1;
1006
}
1007
1008
/* 'c' completion output started */
1009
else if ( ch == 'c' )
1010
{
1011
GapState = GAP_RUNNING;
1012
UpdateMenus(GapState);
1013
UpdateXCMDS(True);
1014
LastLine = -1;
1015
}
1016
1017
/* 'h' help output started */
1018
else if ( ch == 'h' )
1019
{
1020
GapState = GAP_HELP;
1021
UpdateMenus(GapState);
1022
UpdateXCMDS(False);
1023
LastLine = -1;
1024
}
1025
1026
/* 'w' is a window command */
1027
else if ( ch == 'w' )
1028
{
1029
long i;
1030
long m;
1031
char * ptr;
1032
char * cmd;
1033
1034
len = 0;
1035
WaitInput(&InBuffer);
1036
ch = READ_CURRENT(InBuffer);
1037
for ( len = 0, m = 1; '0' <= ch && ch <= '9'; m *= 10 ) {
1038
len += (ch-'0') * m;
1039
WaitInput(&InBuffer);
1040
ch = READ_CURRENT(InBuffer);
1041
}
1042
ptr = cmd = XtMalloc(len+1);
1043
i = len;
1044
while ( 0 < i )
1045
{
1046
WaitInput(&InBuffer);
1047
while ( HAS_INPUT(InBuffer) && 0 < i )
1048
{
1049
*ptr++ = READ_CURRENT(InBuffer);
1050
i--;
1051
}
1052
}
1053
*ptr++ = 0;
1054
GapWindowCmd( cmd, len );
1055
XtFree(cmd);
1056
}
1057
1058
/* ignore 'n' for the moment */
1059
else if ( ch == 'n' )
1060
ch = 'n';
1061
1062
/* ignore 'f' for the moment */
1063
else if ( ch == 'f' )
1064
ch = 'f';
1065
1066
/* ignore 's', see 'SimulateInput' */
1067
else if ( ch == 's' ) {
1068
WaitInput(&InBuffer);
1069
(void)READ_CURRENT(InBuffer);
1070
continue;
1071
}
1072
}
1073
1074
/* collect normal characters and display them */
1075
else if ( ' ' <= ch && ch < 127 && GapState == GAP_RUNNING )
1076
{
1077
TBuf[0] = ch;
1078
for ( len = 1; len<SIZE_BUFFER && HAS_BUFFERED(InBuffer); )
1079
if ( CURRENT(InBuffer) == '@' )
1080
{
1081
if ( LOOK_AHEAD(InBuffer) == 'n' )
1082
{
1083
(void)READ_CURRENT(InBuffer);
1084
/* WaitInput(&InBuffer); */
1085
(void)READ_CURRENT(InBuffer);
1086
}
1087
else if ( LOOK_AHEAD(InBuffer) == 'f' )
1088
{
1089
(void)READ_CURRENT(InBuffer);
1090
/* WaitInput(&InBuffer); */
1091
(void)READ_CURRENT(InBuffer);
1092
}
1093
else if ( LOOK_AHEAD(InBuffer) == 'J' )
1094
{
1095
(void)READ_CURRENT(InBuffer);
1096
/* WaitInput(&InBuffer); */
1097
(void)READ_CURRENT(InBuffer);
1098
TBuf[len++] = '\n';
1099
}
1100
else
1101
break;
1102
}
1103
else if ( ' '<=CURRENT(InBuffer) && CURRENT(InBuffer)<127 )
1104
TBuf[len++] = READ_CURRENT(InBuffer);
1105
else
1106
break;
1107
GTReplaceText( GapTalk, TBuf, len );
1108
}
1109
1110
/* collect normal characters and display them */
1111
else if ( ' ' <= ch && ch < 127 && GapState != GAP_RUNNING )
1112
{
1113
TBuf[0] = ch;
1114
for ( len = 1; len<SIZE_BUFFER && HAS_INPUT(InBuffer); len++ )
1115
if ( CURRENT(InBuffer) == '@' )
1116
break;
1117
else if ( ' '<=CURRENT(InBuffer) && CURRENT(InBuffer)<127 )
1118
TBuf[len] = READ_CURRENT(InBuffer);
1119
else
1120
break;
1121
GTReplaceText( GapTalk, TBuf, len );
1122
}
1123
1124
/* carriage return */
1125
else if ( ch == '\n' )
1126
{
1127
if ( GapState != GAP_INPUT && GapState != GAP_ERROR )
1128
GTReplaceText( GapTalk, &ch, 1 );
1129
}
1130
1131
/* <CTR-G> rings a bell */
1132
else if ( ch == CTR('G') )
1133
GTBell(GapTalk);
1134
1135
/* <CTR-H> moves to the left */
1136
else if ( ch == CTR('H') )
1137
GTMoveCaret( GapTalk, -1 );
1138
1139
/* ignore anything else */
1140
else
1141
ch = ch;
1142
}
1143
}
1144
1145
1146
/****************************************************************************
1147
**
1148
1149
*F * * * * * * * * * * * * starting/stopping gap + * * * * * * * * * * * * *
1150
*/
1151
1152
1153
/****************************************************************************
1154
**
1155
1156
*F KillGap() . . . . . . . . . . . . . . . . . . . . . kill the running gap
1157
*/
1158
void KillGap ()
1159
{
1160
if ( GapPID != -1 )
1161
{
1162
close(ToGap);
1163
kill( GapPID, SIGKILL );
1164
}
1165
}
1166
1167
1168
/****************************************************************************
1169
**
1170
*F InterruptGap() . . . . . . . . . . . . . . . . interupt the running gap
1171
*/
1172
void InterruptGap ()
1173
{
1174
if ( GapPID != -1 )
1175
kill( GapPID, SIGINT );
1176
}
1177
1178
1179
/****************************************************************************
1180
**
1181
*F GetMasterPty( <fid> ) . . . . . . . . . open a master pty (from "xterm")
1182
*/
1183
static String ptydev = 0;
1184
static String ttydev = 0;
1185
1186
#ifndef SYS_PTYDEV
1187
# ifdef hpux
1188
# define SYS_PTYDEV "/dev/ptym/ptyxx"
1189
# else
1190
# define SYS_PTYDEV "/dev/ptyxx"
1191
# endif
1192
#endif
1193
1194
#ifndef SYS_TTYDEV
1195
# ifdef hpux
1196
# define SYS_TTYDEV "/dev/pty/ttyxx"
1197
# else
1198
# define SYS_TTYDEV "/dev/ttyxx"
1199
# endif
1200
#endif
1201
1202
#ifndef SYS_PTYCHAR1
1203
# ifdef hpux
1204
# define SYS_PTYCHAR1 "zyxwvutsrqp"
1205
# else
1206
# define SYS_PTYCHAR1 "pqrstuvwxyz"
1207
# endif
1208
#endif
1209
1210
#ifndef SYS_PTYCHAR2
1211
# ifdef hpux
1212
# define SYS_PTYCHAR2 "fedcba9876543210"
1213
# else
1214
# define SYS_PTYCHAR2 "0123456789abcdef"
1215
# endif
1216
#endif
1217
1218
1219
static Boolean GetMasterPty ( pty )
1220
int * pty;
1221
{
1222
#if HAVE_GETPT && HAVE_PTSNAME_R
1223
if ((*pty = getpt()) > 0 )
1224
{
1225
if (grantpt(*pty) || unlockpt(*pty))
1226
return True;
1227
ptsname_r(*pty, ttydev, 80);
1228
return False;
1229
}
1230
return True;
1231
#else
1232
# ifdef att
1233
if ( (*pty = open( "/dev/ptmx", O_RDWR )) < 0 )
1234
return True;
1235
return False;
1236
1237
# else
1238
# ifdef __CYGWIN__
1239
static int slave = 0;
1240
1241
sprintf(ptydev, "/dev/ptmx");
1242
if ( (*pty = open( ptydev, O_RDWR )) >= 0 ) {
1243
/* O_NONBLOCK | O_NOCTTY */
1244
strcpy(ttydev, ptsname(*pty));
1245
revoke(ttydev); /* ???? NECESSARY ???? */
1246
return False;
1247
}
1248
errno = ENOENT; /* out of ptys */
1249
perror(" Failed on open CYGWIN pty");
1250
return True;
1251
# else
1252
# if HAVE_GETPSEUDOTTY
1253
return (*pty = getpseudotty( &ttydev, &ptydev )) >= 0 ? False : True;
1254
1255
# else
1256
# if HAVE__GETPTY
1257
char * line;
1258
1259
line = _getpty(pty, O_RDWR|O_NDELAY, 0600, 0) ;
1260
if (0 == line)
1261
return True;
1262
strcpy( ttydev, line );
1263
return False;
1264
1265
# else
1266
# if defined(sgi) || (defined(umips) && defined(USG))
1267
struct stat fstat_buf;
1268
1269
*pty = open( "/dev/ptc", O_RDWR );
1270
if ( *pty < 0 || (fstat (*pty, &fstat_buf)) < 0 )
1271
return True;
1272
sprintf( ttydev, "/dev/ttyq%d", minor(fstat_buf.st_rdev) );
1273
# if !defined(sgi)
1274
sprintf( ptydev, "/dev/ptyq%d", minor(fstat_buf.st_rdev) );
1275
if ( (*tty = open (ttydev, O_RDWR)) < 0 )
1276
{
1277
close (*pty);
1278
return True;
1279
}
1280
# endif
1281
return False;
1282
1283
# else
1284
static int devindex = 0;
1285
static int letter = 0;
1286
static int slave = 0;
1287
1288
while ( SYS_PTYCHAR1[letter] )
1289
{
1290
ttydev[strlen(ttydev)-2] = SYS_PTYCHAR1[letter];
1291
ptydev[strlen(ptydev)-2] = SYS_PTYCHAR1[letter];
1292
1293
while ( SYS_PTYCHAR2[devindex] )
1294
{
1295
ttydev[strlen(ttydev)-1] = SYS_PTYCHAR2[devindex];
1296
ptydev[strlen(ptydev)-1] = SYS_PTYCHAR2[devindex];
1297
1298
if ( (*pty = open( ptydev, O_RDWR )) >= 0 )
1299
if ( (slave = open( ttydev, O_RDWR, 0 )) >= 0 )
1300
{
1301
close(slave);
1302
(void) devindex++;
1303
return False;
1304
}
1305
devindex++;
1306
}
1307
devindex = 0;
1308
(void) letter++;
1309
}
1310
return True;
1311
# endif
1312
# endif
1313
# endif
1314
# endif
1315
# endif
1316
#endif
1317
}
1318
1319
1320
/****************************************************************************
1321
**
1322
*F StartGapProcess( <name>, <argv> ) . . . start a gap subprocess using ptys
1323
*/
1324
static void GapStatusHasChanged ()
1325
{
1326
# ifdef SYS_HAS_UNION_WAIT
1327
union wait w;
1328
# else
1329
int w;
1330
# endif
1331
1332
/* if the child was stopped return */
1333
if ( wait3( &w, WNOHANG | WUNTRACED, 0 ) != GapPID || WIFSTOPPED(w) )
1334
return;
1335
# ifdef DEBUG_ON
1336
fputs( "gap status has changed, leaving xgap\n", stderr );
1337
fprintf( stderr,"Signal: %d\n",WTERMSIG(w));
1338
# endif
1339
exit(1);
1340
}
1341
1342
int StartGapProcess ( name, argv )
1343
String name;
1344
String argv[];
1345
{
1346
Int j; /* loop variables */
1347
char c[8]; /* buffer for communication */
1348
int master; /* pipe to GAP */
1349
int n; /* return value of 'select' */
1350
int slave; /* pipe from GAP */
1351
/* struct */ fd_set fds; /* for 'select' */
1352
struct timeval timeout; /* time to wait for aknowledgement */
1353
1354
# if HAVE_TERMIOS_H
1355
struct termios tst; /* old and new terminal state */
1356
# else
1357
# if HAVE_TERMIO_H
1358
struct termio tst; /* old and new terminal state */
1359
# else
1360
struct sgttyb tst; /* old and new terminal state */
1361
# endif
1362
# endif
1363
1364
/* construct the name of the pseudo terminal */
1365
/* was:
1366
ttydev = XtMalloc(strlen(SYS_TTYDEV)+1); strcpy( ttydev, SYS_TTYDEV );
1367
ptydev = XtMalloc(strlen(SYS_PTYDEV)+1); strcpy( ptydev, SYS_PTYDEV );
1368
changed by Max 2.5.2004 because this might be too short! */
1369
ttydev = XtMalloc(81); strcpy( ttydev, SYS_TTYDEV );
1370
ptydev = XtMalloc(81); strcpy( ptydev, SYS_PTYDEV );
1371
1372
/* open pseudo terminal for communication with gap */
1373
if ( GetMasterPty(&master) )
1374
{
1375
fputs( "open master failed\n", stderr );
1376
exit(1);
1377
}
1378
if ( (slave = open( ttydev, O_RDWR, 0 )) < 0 )
1379
{
1380
fputs( "open slave failed\n", stderr );
1381
exit(1);
1382
}
1383
# if defined(DEBUG_ON) && !defined(att)
1384
DEBUG( D_COMM, ("StartGapProcess: master='%s', slave='%s'\n",
1385
ptydev ? ptydev : "unknown",
1386
ttydev ? ttydev : "unkown") );
1387
# endif
1388
# if HAVE_TERMIOS_H
1389
if ( tcgetattr( slave, &tst ) == -1 )
1390
{
1391
fputs( "tcgetattr on slave pty failed\n", stderr );
1392
exit(1);
1393
}
1394
tst.c_cc[VINTR] = 0377;
1395
tst.c_cc[VQUIT] = 0377;
1396
tst.c_iflag &= ~(INLCR|ICRNL);
1397
tst.c_cc[VMIN] = 1;
1398
tst.c_cc[VTIME] = 0;
1399
tst.c_lflag &= ~(ECHO|ICANON);
1400
if ( tcsetattr( slave, TCSANOW, &tst ) == -1 )
1401
{
1402
fputs( "tcsetattr on slave pty failed\n", stderr );
1403
exit(1);
1404
}
1405
# else
1406
# if HAVE_TERMIO_H
1407
if ( ioctl( slave, TCGETA, &tst ) == -1 )
1408
{
1409
fputs( "ioctl TCGETA on slave pty failed\n", stderr );
1410
exit(1);
1411
}
1412
tst.c_cc[VINTR] = 0377;
1413
tst.c_cc[VQUIT] = 0377;
1414
tst.c_iflag &= ~(INLCR|ICRNL);
1415
tst.c_cc[VMIN] = 1;
1416
tst.c_cc[VTIME] = 0;
1417
/* Note that this is at least on Linux dangerous!
1418
Therefore, we now have the HAVE_TERMIOS_H section for POSIX
1419
Terminal control. */
1420
tst.c_lflag &= ~(ECHO|ICANON);
1421
if ( ioctl( slave, TCSETAW, &tst ) == -1 )
1422
{
1423
fputs( "ioctl TCSETAW on slave pty failed\n", stderr );
1424
exit(1);
1425
}
1426
# else
1427
if ( ioctl( slave, TIOCGETP, (char*)&tst ) == -1 )
1428
{
1429
if ( ttydev )
1430
fprintf( stderr, "ioctl TIOCGETP on slave pty failed (%s)\n",
1431
ttydev );
1432
else
1433
fputs( "ioctl TIOCGETP on slave pty failed\n", stderr );
1434
exit(1);
1435
}
1436
tst.sg_flags |= RAW;
1437
tst.sg_flags &= ~ECHO;
1438
if ( ioctl( slave, TIOCSETN, (char*)&tst ) == -1 )
1439
{
1440
fputs( "ioctl on TIOCSETN slave pty failed\n", stderr );
1441
exit(1);
1442
}
1443
#endif
1444
#endif
1445
1446
/* set input to non blocking operation */
1447
if ( fcntl( master, F_SETFL, O_NDELAY ) < 0 )
1448
{
1449
fputs( "Panic: cannot set non blocking operation.\n", stderr );
1450
exit(1);
1451
}
1452
1453
/* fork to gap, dup pipe to stdin and stdout */
1454
GapPID = fork();
1455
if ( GapPID == 0 )
1456
{
1457
dup2( slave, 0 );
1458
dup2( slave, 1 );
1459
/* The following is necessary because otherwise the GAP process
1460
will ignore the SIGINT signal: */
1461
signal( SIGINT, SIG_DFL );
1462
# ifdef SYS_HAS_EXECV_CCHARPP
1463
execv( name, (const char**) argv );
1464
# else
1465
execv( name, (void*) argv );
1466
# endif
1467
if (write( 1, "@-", 2) < 2) fputs("Child: Cannot write @-", stderr);
1468
close(slave);
1469
_exit(1);
1470
}
1471
ToGap = master;
1472
FromGap = master;
1473
1474
/* check if the fork was successful */
1475
if ( GapPID == -1 )
1476
{
1477
fputs( "Panic: cannot fork to subprocess.\n", stderr );
1478
exit(1);
1479
}
1480
1481
/* wait at least 60 sec before giving up */
1482
timeout.tv_sec = 60;
1483
timeout.tv_usec = 0;
1484
1485
/* wait for an aknowledgement (@p) from the gap subprocess */
1486
j = 0;
1487
while ( j < 10 && c[j-1] != '.' )
1488
{
1489
1490
/* set <FromGap> port for listen */
1491
# ifdef FD_SET
1492
FD_ZERO(&fds);
1493
FD_SET( FromGap, &fds );
1494
# else
1495
{
1496
Int i;
1497
1498
for ( i = FromGap/sizeof(fds.fds_bits); 0 <= i; i-- )
1499
fds.fds_bits[i] = 0;
1500
fds.fds_bits[FromGap/sizeof(fds.fds_bits)] =
1501
( 1 << (FromGap % sizeof(fds.fds_bits)) );
1502
}
1503
# endif
1504
1505
/* use 'select' to check port */
1506
if ( (n = select(FromGap+1, &fds, 0, 0, &timeout)) == -1 )
1507
{
1508
kill( GapPID, SIGKILL );
1509
perror("select failed");
1510
exit(1);
1511
}
1512
else if ( n == 0 )
1513
{
1514
kill( GapPID, SIGKILL );
1515
fputs("Panic: cannot establish communication with gap.", stderr);
1516
exit(1);
1517
}
1518
else
1519
ReadGap( &(c[j++]), 1 );
1520
}
1521
1522
/* check if we got "@p" */
1523
if ( c[j-1] != '.' || strncmp( c, "@p", 2 ) )
1524
{
1525
if ( ! strncmp( c, "@-", 2 ) )
1526
{
1527
fputs( "Panic: cannot start subprocess ", stderr );
1528
fputs( name, stderr );
1529
fputs( ".\n", stderr );
1530
}
1531
else
1532
{
1533
strcpy( c+3, "'\n" );
1534
fputs( "Panic: cannot talk with gap, got '", stderr );
1535
fputs( c, stderr );
1536
kill( GapPID, SIGKILL );
1537
}
1538
exit(1);
1539
}
1540
1541
/* if the gap dies, stop program */
1542
signal( SIGCHLD, GapStatusHasChanged );
1543
InBuffer.pos = InBuffer.len = 0;
1544
return FromGap;
1545
}
1546
1547
1548
/****************************************************************************
1549
**
1550
1551
*E pty.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ends here
1552
*/
1553
1554