-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathmchan.c.old
1540 lines (1371 loc) · 38.7 KB
/
mchan.c.old
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* These procedures hope to give EMACS a facility for dealing with multiple
processes in a reasonable way */
/* Copyright (c) 1981 Carl Ebeling */
/* Modified 8-Sept-81 Jeffrey Mogul (JCM) at Stanford
* - removed RstDsp() after failure to open mpx file; this
* was leading to nasty infinite loop. Probably this should
* be done better and in other situations as well.
*/
/* Modified by Chris Torek (ACT) at umcp-cs to answer more ioctls */
/* Modified 17-Jul-82 ACT - rewrote the emacs-share to automatically
* create buffers for process that access the multiplexed file. Also
* changed the definition of '-s' from 'use share' to 'don't use share'
* with the default being 'use share'.
*/
/* ACT 22-Jul-82: added variable 'emacs-share' (I suspect this used to
* exist!), default 1, which lets/prevents opens of the share file
*/
/* ACT 21-Oct-1982 adding code to let csh do job control.... */
/* Incorporate Umcp-Cs features to get a really nice version of mchan.c
for 4.1bsd */
/* Original changes for 4.2bsd (c) 1982 William N. Joy and Regents of UC */
/* More changes for 4.1aBSD by Spencer Thomas of Utah-Cs */
/* Still more changes for 4.1aBSD by Marshall Rose of UCI */
/* Changes for 4.1cBSD by Chris Kent of DecWRL */
#include "config.h"
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <wait.h>
#include <sgtty.h>
#include <time.h>
#include <sys/types.h>
#include "window.h"
#include "keyboard.h"
#include "buffer.h"
#include "mlisp.h"
#include "macros.h"
#include "mchan.h"
char *malloc();
#ifndef titan
typedef long * waddr_t;
#endif
#ifdef subprocesses
#define ChunkSize 500 /* amount to truncate when buffer overflows */
#ifndef TTYconnect
static PopUpUnexpected; /* True iff unexpected opens pop up windows */
static EmacsShare; /* Share flag, true iff opens allowed */
static struct BoundName
*UnexpectedProc; /* What to do with unexpected procs */
static struct BoundName
*UnexpectedSent; /* What to do when unexpected procs exit */
#else
int PopUpUnexpected; /* True iff unexpected opens pop up windows */
int EmacsShare; /* Share flag, true iff opens allowed */
struct BoundName
*UnexpectedProc; /* What to do with unexpected procs */
struct BoundName
*UnexpectedSent; /* What to do when unexpected procs exit */
#endif
static ProcessBufferSize; /* Maximum size for process buffer */
int sel_ichans; /* input channels */
int sel_ochans; /* blocked output channels */
static struct sgttyb mysgttyb;
static struct tchars mytchars;
static struct ltchars myltchars;
static int mylmode;
#ifdef ce
FILE *err_file; /* Debugging file */
int err_id; /* User's ID for error messages */
#endif
struct channel_blk
stdin_chan;
int child_changed; /* Flag when a child process changes status */
struct VariableName
*MPX_process;
struct channel_blk
*MPX_chan;
char *SIG_names[] = { /* descriptive (?) names of signals */
"",
"Hangup",
"Interrupt",
"Quit",
"Illegal instruction",
"Trace/BPT trap",
"IOT trap",
"EMT trap",
"Floating exception",
"Killed",
"Bus error",
"Segmentation fault",
"Bad system call",
"Broken pipe",
"Alarm clock",
"Terminated",
#ifdef SIGURG
"Urgent I/O condition",
#else
"Signal 16",
#endif
"Stopped (signal)",
"Stopped",
"Continued", /* */
"Child exited", /* */
"Stopped (tty input)", /* */
"Stopped (tty output)", /* */
"Tty input interrupt", /* */
"Cputime limit exceeded",
"Filesize limit exceeded",
"Signal 26",
"Signal 27",
"Signal 28",
"Signal 29",
"Signal 30",
"Signal 31",
"Signal 32"
};
static char *KillNames[] = { /* names used for signal-to-process */
"", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT", "EMT",
"FPE", "KILL", "BUS", "SEGV", "SYS", "PIPE", "ALRM", "TERM",
#ifdef SIGURG
"URG",
#else
"",
#endif
"STOP", "TSTP", "CONT", "CHLD", "TTIN", "TTOU",
#ifdef SIGTINT
"TINT",
#else
#ifdef SIGIO
"IO",
#else
"",
#endif
#endif
"XCPU", "XFSZ"
};
char *
pty(ptyv)
int *ptyv;
{
#include <sys/stat.h>
struct stat stb;
static char name[24];
int on = 1, i;
strcpy(name, "/dev/ptypX");
for (;;) {
name[strlen("/dev/ptyp")] = '0';
if (stat(name, &stb) < 0)
return (0);
for (i = 0; i < 16; i++) {
name[strlen("/dev/ptyp")] = "0123456789abcdef"[i];
*ptyv = open(name, 2);
if (*ptyv >= 0) {
/* If the following statement is included,
* then a 0 length record is EOT, but no other
* control characters can be sent down the pty
* (e.g., ^S/^Q, ^O, etc.). If it is not
* included, then sending ^D down the pty-pipe
* makes a pretty good EOF.
*/
/* ioctl(*ptyv, TIOCREMOTE, (waddr_t)&on);/* for EOT */
ioctl(*ptyv, FIONBIO, (waddr_t)&on);
name[strlen("/dev/")] = 't';
return (name);
}
}
name[strlen("/dev/pty")]++;
}
}
/* Start up a subprocess with its standard input and output connected to
a channel on the mpx file. Also set its process group so we can kill it
and set up its process block. The process block is assumed to be pointed
to by current_process. */
create_process (command)
register char *command;
{
index_t channel;
int pgrp,
len,
ld;
char *ptyname;
register pid;
extern char *shell ();
extern UseCshOptionF;
#ifdef UciFeatures
extern UseUsersShell;
#endif
ptyname = pty (&channel);
if (ptyname == 0) {
error ("Can't get a pty");
return (-1);
}
sel_ichans |= 1<<channel;
#ifdef HalfBaked
sighold (SIGINT);
#endif
if ((pid = vfork ()) < 0) {
error ("Fork failed");
close (channel);
sel_ichans &= ~(1<<channel);
#ifdef DEBUG
sigrelse(SIGINT);
#endif
return (-1);
}
if (pid == 0) {
#ifdef ce
fprintf (err_file, "Creating pid %d on %s\n", getpid (), ptyname);
#endif
close (channel);
sigrelse (SIGCHLD);
setpgrp (0, getpid ());
sigsys (SIGINT, SIG_DFL);
sigsys (SIGQUIT, SIG_DFL);
if ((ld = open ("/dev/tty", 2)) >= 0) {
ioctl (ld, TIOCNOTTY, (waddr_t)0);
close (ld);
}
close (2);
if (open (ptyname, 2) < 0) {
write (1, "Can't open subprocess tty ", 26);
write (1, ptyname, strlen(ptyname));
_exit (1);
}
pgrp = getpid();
ioctl (2, TIOCSPGRP, (waddr_t)&pgrp);
close (0);
close (1);
dup (2);
dup (2);
ioctl (0, TIOCSETP, (waddr_t)&mysgttyb);
ioctl (0, TIOCSETC, (waddr_t)&mytchars);
ioctl (0, TIOCSLTC, (waddr_t)&myltchars);
ioctl (0, TIOCLSET, (waddr_t)&mylmode);
len = 0; /* set page features to 0 */
#ifdef TIOCSWID
ioctl (0, TIOCSWID, (waddr_t)&len); /* page width */
#endif
#ifdef TIOCSLEN
ioctl (0, TIOCSLEN, (waddr_t)&len); /* page len (CCA uses TIOCSSCR) */
#endif
#ifdef UciFeatures
len = UseUsersShell;
UseUsersShell = 1;
#endif
ld = strcmp(shell(), "/bin/csh") ? OTTYDISC : NTTYDISC;
ioctl (0, TIOCSETD, (waddr_t)&ld);
#ifdef UciFeatures
UseUsersShell = len;
#endif
#ifndef UciFeatures
execlp (shell (), shell (), UseCshOptionF ? "-cf" : "-c", command, 0);
#else
execlp (shell (), shell (),
UseUsersShell && UseCshOptionF ? "-cf" : "-c", command, 0);
#endif
write (1, "Couldn't exec the shell\n", 24);
_exit (1);
}
#ifdef HalfBaked
sigrelse (SIGINT);
#endif
current_process -> p_name = command;
current_process -> p_pid = pid;
current_process -> p_gid = pid;
#ifndef UtahFeatures
current_process -> p_flag = RUNNING;
#else
current_process -> p_flag = RUNNING | CHANGED;
child_changed++;
#endif
current_process -> p_reason = 0;
current_process -> p_chan.ch_index = channel;
current_process -> p_chan.ch_ptr = NULL;
current_process -> p_chan.ch_count = 0;
current_process -> p_chan.ch_outrec.index = channel;
current_process -> p_chan.ch_outrec.count = 0;
current_process -> p_chan.ch_outrec.ccount = 0;
return 0;
}
#endif
/* Process a signal from a child process and make the appropriate change in
the process block. Since signals are NOT queued, if two signals are
received before this routine gets called, then only the first process in
the process list will be handled. We will try to get the MPX file stuff
to help us out since it passes along signals from subprocesses.
*/
int subproc_id; /* The process id of a subprocess
started by the old subproc stuff.
We will zero it so they will know it
has finished */
child_sig () {
register int pid;
union wait w;
register struct process_blk *p;
extern struct process_blk *get_next_process ();
loop:
pid = wait3 (&w.w_status, WUNTRACED | WNOHANG, 0);
#ifdef ce
fprintf(err_file, "Wait3 pid %d w_status 0x%x\n", pid, w.w_status);
#endif
if (pid <= 0) {
if (errno == EINTR) {
errno = 0;
goto loop;
}
#ifdef subprocesses
if (pid == -1) {
if (!active_process (current_process))
current_process = get_next_process ();
}
#endif
return;
}
if (pid == subproc_id) { /* It may not be our progeny */
subproc_id = 0; /* Take care of those subprocesses first
*/
goto loop;
}
#ifndef subprocesses
goto loop;
}
#else
for (p = process_list; p != NULL; p = p -> next_process)
if (pid == p -> p_pid)
break;
if (p == NULL)
goto loop; /* We don't know who this is */
if (WIFSTOPPED (w)) {
#ifndef UtahFeatures
p -> p_flag = STOPPED;
#else
p -> p_flag = STOPPED | CHANGED;
#endif
p -> p_reason = w.w_stopsig;
#ifdef UtahFeatures
child_changed++;
#endif
}
else
if (WIFEXITED (w)) {
p -> p_flag = EXITED | CHANGED;
child_changed++;
p -> p_reason = w.w_retcode;
}
else
if (WIFSIGNALED (w)) {
p -> p_flag = SIGNALED | CHANGED;
if (w.w_coredump)
p -> p_flag |= COREDUMPED;
child_changed++;
p -> p_reason = w.w_termsig;
}
if (!active_process (current_process))
current_process = get_next_process ();
goto loop;
}
/* Find the process which is connected to buf_name */
struct process_blk *find_process (buf_name)
register char *buf_name;
{
register struct process_blk *p;
if (buf_name == NULL)
return (NULL);
for (p = process_list; p != NULL; p = p -> next_process) {
if (!active_process (p))
continue;
if (strcmp (p -> p_chan.ch_buffer -> b_name, buf_name) == 0)
break;
}
return (p);
}
/* Get the first active process in the process list and assign to the current
process */
struct process_blk *get_next_process () {
register struct process_blk *p;
for (p = process_list; p && !active_process (p); p = p -> next_process);
return p;
}
/* This corresponds to the filbuf routine used by getchar. This handles all
the input from the mpx file. Input coming from the terminal is sent back
to getchar() in the same manner as filbuf. Control messages are sent to
Take_msg for interpretation. Normal input from other channels is routed
to the correct buffer. */
static char cbuffer[BUFSIZ]; /* used for reading mpx file */
static int mpx_count; /* number of unprocessed characters in
buffer */
/* ARGSUSED */
#ifdef ECHOKEYS
fill_chan (chan, alrmtime)
#else
fill_chan (chan)
#endif
register struct channel_blk *chan;
{
int ichans, ochans, cc;
register struct channel_blk *this_chan;
register struct process_blk *p;
struct timeval timeout;
#ifdef ECHOKEYS
if (alrmtime <= 0 || alrmtime > 100000000)
alrmtime = 100000;
#endif
readloop:
if (err != 0) /* check for ^G interrupts */
return 0;
ichans = sel_ichans; ochans = sel_ochans;
if (chan == NULL)
ichans &= ~1; /* don't look at tty in this case */
/*
* If we do this here, iff there is no input, then it will always
* happen asap.
*/
if (child_changed) {
int c_ichans = ichans;
timeout.tv_sec = 0; timeout.tv_usec = 0;
if (select(32, &c_ichans, 0, 0, &timeout) <= 0) /* if none waiting */
{
change_msgs ();
child_changed = 0;
}
}
#ifdef ECHOKEYS
timeout.tv_sec = alrmtime; timeout.tv_usec = 0;
if ((cc = select(32, &ichans, &ochans, 0, &timeout)) < 0)
goto readloop; /* try again */
else
if (cc == 0)
EchoThem (1);
#else
timeout.tv_sec = 100000; timeout.tv_usec = 0;
if (select(32, &ichans, &ochans, 0, &timeout) < 0)
goto readloop; /* try again */
#endif
#ifdef TTYconnect
AttachSocket (ichans); /* check for a new socket */
#endif
if (ichans&1) {
ichans &= ~1;
cc = read(0, cbuffer, sizeof (cbuffer));
if (cc > 0) {
if (child_changed) {
change_msgs ();
child_changed = 0;
}
mpxin->ch_ptr = cbuffer;
mpxin->ch_count = cc - 1;
stdin->_flag &= ~_IOEOF;
return (*mpxin->ch_ptr++ & 0377);
}
else if (cc == 0)
{
fprintf(stderr,"null read from stdin\r\n");
stdin->_flag |= _IOEOF; /* mark EOF encountered */
return(EOF);
}
}
for (p = process_list; p != NULL; p = p->next_process) {
this_chan = &p->p_chan;
if (ichans & (1<<this_chan->ch_index)) {
ichans &= ~(1<<this_chan->ch_index);
cc = read(this_chan->ch_index, cbuffer, sizeof (cbuffer));
if (cc > 0) {
this_chan->ch_ptr = cbuffer;
this_chan->ch_count = cc;
stuff_buffer(this_chan);
}
else if (cc <= 0)
{
/* With pty:s, when the parent process of a pty exits we are notified,
just as we would be with any of our other children. After the process
exits, select() will indicate that we can read the channel. When we
do this, read() returns 0. Upon receiving this, we close the channel.
For unexpected processes, when the peer closes the connection, select()
will indicate that we can read the channel. When we do this, read()
returns -1 with errno = ECONNRESET. Since we never get notified of
this via wait3(), we must explictly mark the process as having exited.
(This corresponds to the action performed when a M_CLOSE is received
with the MPXio version of Emacs.)
*/
#ifdef ce
extern int errno;
fprintf (err_file, "%s read from %s on channel %d errno=%d\n",
cc == 0 ? "null" : "error", p -> p_name,
this_chan -> ch_index, cc < 0 ? errno : 0);
#endif
sel_ichans &= ~(1 << this_chan -> ch_index); /* disconnect */
sel_ochans &= ~(1 << this_chan -> ch_index); /* disconnect */
close (this_chan->ch_index);
#ifdef TTYconnect
if (cc < 0) { /* peer dropped it */
#ifndef UtahFeatures
p -> p_flag = EXITED;
p -> p_reason = 0;
#else
p -> p_flag = EXITED | CHANGED;
p -> p_reason = 0;
child_changed++;
#endif
}
#endif
}
}
if (ochans & (1<<this_chan->ch_index)) {
ochans &= ~(1<<this_chan->ch_index);
if (this_chan->ch_outrec.ccount) {
cc = write(this_chan->ch_index, "", 0);
if (cc < 0)
continue;
this_chan->ch_outrec.ccount = 0;
}
if (this_chan->ch_outrec.count) {
cc = write(this_chan->ch_index,
this_chan->ch_outrec.data, this_chan->ch_outrec.count);
if (cc > 0) {
this_chan->ch_outrec.data += cc;
this_chan->ch_outrec.count -= cc;
}
}
if (this_chan->ch_outrec.count == 0)
sel_ochans &= ~(1<<this_chan->ch_index);
}
}
/* SWT - do this after stuffing output. Hopefully the "Exited"
* message will always come at the end of the buffer then.
*/
#ifdef UtahFeatures
if (child_changed) {
change_msgs ();
child_changed = 0;
}
#endif
if (chan != NULL)
goto readloop;
#ifdef UtahFeatures
return 0;
#endif
}
/* Give a message that a process has changed and indicate why. Dead processes
are not removed until after a Display Processes command has been issued so
that the user doesn't wonder where his process went in times of intense
hacking. */
change_msgs () {
register struct process_blk *p;
register struct buffer *old = bf_cur;
int sent = 0; /* if non-zero, call sentinel */
char line[50];
#ifdef HalfBaked
sighold (SIGINT);
#endif
for (p = process_list; p != NULL; p = p -> next_process)
if (p -> p_flag & CHANGED) {
sent = 0;
p -> p_flag &= ~CHANGED;
switch (p -> p_flag & (SIGNALED | EXITED)) {
case SIGNALED:
SetBfp (p -> p_chan.ch_buffer);
SetDot (bf_s1 + bf_s2 + 1);
sprintfl (line, sizeof line, "%s%s\n",
SIG_names[p -> p_reason],
p -> p_flag & COREDUMPED ? " (core dumped)" : "");
if (p->p_chan.ch_sent == NULL)
InsStr (line);
else
sent++; /* call sentinel */
break;
case EXITED:
SetBfp (p -> p_chan.ch_buffer);
SetDot (bf_s1 + bf_s2 + 1);
sprintfl (line, sizeof line,
p -> p_reason ? "Exit %d\n" : "Exited\n",
p -> p_reason);
if (p -> p_chan.ch_sent == NULL)
InsStr (line);
else
sent++;
break;
}
if (p->p_flag & RUNNING)
{
strcpy(line, "Running\n");
sent++;
}
if (p->p_flag & STOPPED)
{
strcpy(line, "Stopped\n");
sent++;
}
if (p->p_chan.ch_sent != NULL && sent)
{
register Expression * MPX_Exp =
MPX_process -> v_binding -> b_exp;
int larg = arg;
enum ArgStates lstate = ArgState;
int old_int = MPX_Exp -> exp_int;
char *old_str = MPX_Exp -> exp_v.v_string;
register struct channel_blk *chan =
&(p -> p_chan);
register struct channel_blk *oldchan = MPX_chan;
arg = p -> p_reason | (p->p_flag << 16);
ArgState = HaveArg;
MPX_Exp -> exp_int =
strlen (chan -> ch_buffer -> b_name);
MPX_Exp -> exp_v.v_string =
chan -> ch_buffer -> b_name;
/* Set up so user can get string reason as well */
chan->ch_ptr = line;
chan->ch_count = strlen(line);
MPX_chan = chan;
ExecuteBound (chan -> ch_sent);
MPX_chan = oldchan;
chan->ch_ptr = NULL;
chan->ch_count = 0;
MPX_Exp -> exp_int = old_int;
MPX_Exp -> exp_v.v_string = old_str;
arg = larg;
ArgState = lstate;
}
}
#ifdef HalfBaked
sigrelse (SIGINT);
#endif
DoDsp (1);
SetBfp (old);
}
/* Send any pending output as indicated in the process block to the
appropriate channel.
*/
send_chan (process)
register struct process_blk *process;
{
register struct wh *output;
output = &process -> p_chan.ch_outrec;
if (output -> count == 0 && output -> ccount == 0) {
/* error ("Null output"); */
return 0; /* No output to be done */
}
if (output->ccount) {
if (write(output->index, "", 0) >= 0) {
output->ccount = 0;
return 0;
}
} else {
if (output->count) {
int cc = write(output->index, output->data, output->count);
if (cc > 0) {
output->data += cc;
output->count -= cc;
}
}
if (output->count == 0)
return 0;
}
sel_ochans |= 1<<(output->index);
return 0; /* ACT 8-Sep-1982 */
}
/* Output has been recieved from a process on "chan" and should be stuffed in
the correct buffer */
/* ACT 9-Sep-1982 Modified to remove "lockout" restriction and allow
recursive stuffs. */
stuff_buffer (chan)
register struct channel_blk *chan;
{
struct buffer *old_buffer = bf_cur;
#ifdef HalfBaked
sighold (SIGINT);
#endif
if (chan -> ch_proc == NULL) {
SetBfp (chan -> ch_buffer);
SetDot (bf_s1 + bf_s2 + 1);
InsCStr (chan -> ch_ptr, chan -> ch_count);
if ((bf_s1 + bf_s2) > ProcessBufferSize) {
DelFrwd (1, ChunkSize);
DotLeft (ChunkSize);
}
if (bf_cur -> b_mark == NULL)
bf_cur -> b_mark = NewMark ();
SetMark (bf_cur -> b_mark, bf_cur, dot);
DoDsp (1);
SetBfp (old_buffer);
if (interactive)
WindowOn (bf_cur);
}
else { /* ACT 31-Aug-1982 Added hold on prefix arg */
register char *old_str;
int larg = arg, old_int;
enum ArgStates lstate = ArgState;
register Expression
*MPX_Exp = MPX_process -> v_binding -> b_exp;
struct channel_blk
*old_chan = MPX_chan;
old_int = MPX_Exp -> exp_int;
old_str = MPX_Exp -> exp_v.v_string;
arg = 1;
ArgState = NoArg; /* save arg & arg state */
MPX_Exp -> exp_int = strlen (chan -> ch_buffer -> b_name);
MPX_Exp -> exp_v.v_string = chan -> ch_buffer -> b_name;
MPX_chan = chan; /* User will be able to get the output
for */
ExecuteBound (chan -> ch_proc);
MPX_chan = old_chan; /* a very short time only */
MPX_Exp -> exp_int = old_int;
MPX_Exp -> exp_v.v_string = old_str;
arg = larg;
ArgState = lstate; /* restore arg */
SetBfp (chan -> ch_buffer);
if ((bf_s1 + bf_s2) > ProcessBufferSize) {
DelFrwd (1, ChunkSize);
DotLeft (ChunkSize);
}
SetBfp (old_buffer);
}
chan -> ch_count = 0;
#ifdef HalfBaked
sigrelse (SIGINT);
#endif
return 0; /* ACT 8-Sep-1982 */
}
/* Return a count of all active processes */
count_processes () {
register struct process_blk *p;
register count = 0;
for (p = process_list; p != NULL; p = p -> next_process)
if (active_process (p))
count++;
return (count);
}
/* Flush a process but only if process is inactive */
flush_process (process)
register struct process_blk *process;
{
register struct process_blk *p,
*lp;
if (active_process (process)) {
error ("Can't flush an active process");
return 0;
}
for (lp = NULL, p = process_list;
(p != NULL) && (p != process);
lp = p, p = p -> next_process);
if (p != process) {
error ("Can't find process");
return 0;
}
if (lp == NULL)
process_list = process -> next_process;
else
lp -> next_process = process -> next_process;
free (process);
return 0;
}
/* Kill off all active processes: done only to exit when user really
insists */
kill_processes () {
register struct process_blk *p;
for (p = process_list; p != NULL; p = p -> next_process) {
if (active_process (p)) {
ioctl (p -> p_chan.ch_index, TIOCGPGRP, (waddr_t)&(p -> p_gid));
if (p -> p_gid != -1)
killpg (p -> p_gid, SIGKILL);
if (p -> p_pid != -1)
killpg (p -> p_pid, SIGKILL);
}
}
}
/* Start up a new process by creating the process block and initializing
things correctly */
start_process (com, buf, proc)
register char *com,
*buf;
{
extern struct process_blk *get_next_process ();
if (com == 0)
return 0;
current_process =
(struct process_blk *) malloc (sizeof (struct process_blk));
if (current_process == NULL) {
error ("Out of memory");
return 0;
}
sighold (SIGCHLD);
current_process -> next_process = process_list;
process_list = current_process;
if (create_process (com) < 0) {/* job was not started, so undo */
flush_process (current_process);
current_process = get_next_process ();
sigrelse (SIGCHLD);
return 0;
}
SetBfn (buf == NULL ? "Command execution" : buf);
if (interactive)
WindowOn (bf_cur);
current_process -> p_chan.ch_buffer = bf_cur;
current_process -> p_chan.ch_proc = (proc < 0 ? NULL : MacBodies[proc]);
current_process -> p_chan.ch_sent = NULL;
sigrelse (SIGCHLD);
return 0;
}
/* Emacs command to start up a default process: uses "Command Execution"
buffer if one is not specified. Also does default stuffing */
StartProcess () {
register char *com = (char *) (savestr (getstr ("Command: ")));
register char *buf;
if ((com == 0) || (*com == 0)) {
error ("No command");
return 0;
}
buf = (char *) getstr ("Connect to buffer: ");
if (*buf == 0)
buf = NULL;
start_process (com, buf, -1);
return 0; /* ACT 8-Sep-1982 */
}
/* Start up a process whose output will get filtered through a procedure
specified by the user */
StartFilteredProcess () {
register char *com = (char *) (savestr (getstr ("Command: ")));
register char *buf;
int proc;
char bufname[200];
if ((com == 0) || (*com == 0)) {
error ("No command");
return 0;
}
buf = getstr ("Connect to buffer: ");
if (buf == 0) return 0;
strcpy (bufname, buf);
proc = getword (MacNames, "On-output procedure: ");
start_process (com, bufname[0] ? bufname : NULL, proc);
return 0; /* ACT 8-Sep-1982 */
}
/* Set the UnexpectedProc pointer */
static
SetUnexpectedProc () {
register proc =
getword (MacNames, "Filter unexpected processes through command: ");
UnexpectedProc = proc < 0 ? NULL : MacBodies[proc];
}
/* Return a process buffer or NULL */
struct process_blk *
GetBufProc ()
{
register b = getword (BufNames, "Process: ");
if (b < 0)
return NULL;
return find_process (BufNames[b]);
}
/* Insert a filter-procedure between a process and emacs. This function
should subsume the StartFilteredProcess function, but we should retain
that one for compatibility I suppose. */
InsertFilter ()
{
register struct process_blk *process;
register int proc;
if ((process = GetBufProc ()) == NULL) {
error ("Not a Process");
return 0;
}
proc = getword(MacNames, "On-output procedure: ");
process -> p_chan.ch_proc = (proc < 0 ? NULL : MacBodies[proc]);
return(0);
}
/* Reset filter rebinds the process filter to NULL */
ResetFilter () {
register struct process_blk *process;
if ((process = GetBufProc ()) == NULL) {
error ("Not a Process");
return 0;
}
process -> p_chan.ch_proc = NULL;
return 0; /* ACT 8-Sep-1982 */
}
/* ProcessFilterName returns the name of the process filter */
ProcessFilterName () {
register struct process_blk *process;
char *name;
if ((process = GetBufProc ()) == NULL) {
error ("Not a Process");
return 0;
}
MLvalue -> exp_type = IsString;
MLvalue -> exp_release = 0;
name = process -> p_chan.ch_proc
? process -> p_chan.ch_proc -> b_name : "";
MLvalue -> exp_int = strlen (name);
MLvalue -> exp_v.v_string = name;
return 0;
}
static
InsertSentinel ()
{
register struct process_blk *process;
register int proc;
if ((process = GetBufProc ()) == NULL) {
error ("Not a Process");
return 0;
}
proc = getword(MacNames, "On-exit procedure: ");
process -> p_chan.ch_sent = (proc < 0 ? NULL : MacBodies[proc]);
return(0);