Emacs upgrade part 1
chris at umcp-cs.UUCP
chris at umcp-cs.UUCP
Sun Aug 21 16:24:02 AEST 1983
This is the first of many scripts containing mods to Gosling Emacs
to give it new features, fix a few bugs here and there, and to make
it compatible with 4.1a and 4.1c BSD. (I'm not sure yet just how
many scripts I'll post, since I haven't made all of them yet.)
Instructions will be in one of the later postings.
Chris ("I could swear I left in it /tmp someplace") Torek
-------------------------------------------
: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
all=TRUE
fi
/bin/echo 'Extracting config.h'
sed 's/^X//' <<'//go.sysin dd *' >config.h
X/* Emacs configuration file -- all site-dependant definitions should be made
here. Each site should only have to edit this file. */
#ifndef SystemName
#define SystemName "umcp-cs"
#endif
/* Define this symbol to be a string that
represents the name of your site */
#define BackupExtension ".bak" /* This string gets appended to filenames to
generate the file name used for making
backups. The folks at BBN like to use the
string "~" because it takes up fewer
characters. */
#define CheckpointExtension ".CKP" /* This string gets appended to
filenames to generate the file
name used for making
checkpoints. */
X/* #define PrependExtension /* If this is defined then the backup and
checkpoint extensions will be prepended to
the file name, rather than appended. Some
folks like to use (for example) # as the
first character of a filename to indicate
that it can be deleted if it's more than
a few days old. */
#define subprocesses /* Define this symbol if you want the
subprocess control stuff. This works
on modified 4.1BSD Unix systems, and on
4.1a/4.1c systems. On 4.1, it uses the
mpxio facility.
Even those sites that can run it might not
want to, since it induces people to use
more cycles. */
#ifndef PATH_LOADSEARCH
#define PATH_LOADSEARCH ":/usr/emacs/maclib:/usr/emacs/loclib"
#endif
/* the default search path for loading macro
packages */
#define DefaultProfile "/usr/emacs/maclib/profile.ml"
/* If a user doesn't have a ".emacs_pro" in
their home directory, then the
DefaultProfile file is used as their
profile instead */
#define OneEmacsPerTty /* Define this symbol if only one Emacs is
allowed to run per tty. This is usually
only necessary to get around an obnoxious
bug in the mpxio facility which is used
when the subprocess control feature is
used. If you define subprocesses, then
you should define this symbol -- unless
you have fixed the kernel bug */
#define OneEmacsWarning /* Define this symbol to make it harder for
people to run more than one Emacs. */
#define MailOriginator ((char *) FullNameFromGecos(pw))
X/* #define MailOriginator pw->pw_gecos */
/* MailOriginator should be an expression
that will evaluate to the name of the
originator of a message. "pw" is set to
point to a passwd struct for the current
user. At CMU we put a users full name in
the pw_gecos field, so we use that as the
name for the originator -- our mail system
understands such full names as message
destinations. Other folks might want to
use pw->pw_name. This is also used to
evaluate users-full-name. */
#define AddSiteName /* Define this if you want the name of the
origninating site to be added to the
"from" field of outgoing mail. */
#define CatchSig /* Define this to catch SIGINT and SIGTERM
(although they may have to be sent from
another terminal) */
#define MPXcode /* Define this to get the 4.1BSD mpx-file-
based multiprocessing; otherwise the
4.1[ac] ptys will be used. */
X/* #define TTYconnect /* Define this to get the 4.1[ac] ipc
features for "unexpected" opens. You
always get this when MPXcode is defined. */
#define ECHOKEYS /* Define this to enable echo-keystrokes */
X/* #define BSD41c /* Define this if you are running 4.1c. */
X/* #define LIBNDIR /* Define this to use the directory I/O
library (4.1[ac]). */
#define MaxPathNameLen 500 /* Maximum path name length expected.
Many routines will die if this is
exceeded, so make it big enough!! */
#define EmacsVersionNum 85 /* Version number (for schan.c) -- be sure
to change to 264 if running Emacs #264! */
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 664 config.h
/bin/echo -n ' '; /bin/ls -ld config.h
fi
/bin/echo 'Extracting makefile'
sed 's/^X//' <<'//go.sysin dd *' >makefile
DESTDIR=/usr/local/lib/emacs
EMDESTDIR=/usr/local
LIBES=
# DumpableEmacs is Spencer Thomas's dump-emacs facility
# newmalloc is the CalTech power-of-2 malloc, suitably modified
CFLAGS=-O -R -DNewC -DDumpableEmacs -Dnewmalloc
obj1=buffer.o display.o emacs.o dsp.o window.o keyboard.o simplecoms.o \
minibuf.o fileio.o windowman.o search.o subproc.o metacoms.o \
errlog.o TrmC100.o TrmAmb.o columns.o options.o TrmTERM.o \
macros.o casefiddle.o TrmI400.o mlisp.o ndbm.o \
arithmetic.o abbrev.o sindex.o TrmVT100.o undo.o \
syntax.o TrmMiniB.o TrmTEK4025.o mchan.o pchan.o schan.o \
dbmanager.o abspath.o 2malloc.o unexec.o \
UMfuncs.o filecomp.o TrmBitG.o TrmGT40.o bcopy.o TrmGigi.o sleep.o \
TrmHP.o
obj=lispfuncs.o ${obj1}
cvlobj=cvllispfuncs.o ${obj1}
eeobj=eelispfuncs.o ${obj1}
first: temacs
all: temacs makemail collectmail grep dbadd dbprint dblist \
loadst filesort newloadst
collectmail: collectmail.c sindex.o config.h UMfuncs.o
cc -o collectmail -g collectmail.c sindex.o UMfuncs.o ${LIBES}
makemail: makemail.c config.h UMfuncs.o
cc -o makemail -g makemail.c UMfuncs.o ${LIBES}
temacs: ${obj}
rm -f /tmp/Emacs-
emacs -d -q -l./version.ml -eversion </dev/null >/dev/null
rm -f temacs
cc -z ${CFLAGS} version.c ${obj} -ltermlib -ljobs -o temacs ${LIBES}
cvltemacs: ${cvlobj}
rm -f cvltemacs
cc -z ${CFLAGS} version.c ${cvlobj} -ltermlib -ljobs -o cvltemacs ${LIBES}
eetemacs: ${eeobj}
rm -f eetemacs
cc -z -s ${CFLAGS} version.c ${eeobj} -ltermlib -ljobs -o eetemacs ${LIBES}
pemacs: ${obj}
rm -f pemacs
cc -z -p ${CFLAGS} version.c ${obj} -ltermlib -ljobs -o pemacs ${LIBES}
loadst: loadst.c
cc -O -s -DSETUID loadst.c -o loadst ${LIBES}
chmod u+s loadst
newloadst: loadst.c
cc -O -s -DSETUID -DNEWONLY loadst.c -o newloadst ${LIBES}
chmod u+s newloadst
TrmAmb.o: TrmAmb.c Trm.h keyboard.h
TrmC100.o: TrmC100.c Trm.h display.h
TrmI400.o: TrmI400.c Trm.h
TrmMiniB.o: TrmMiniB.c Trm.h display.h
TrmTEK4025.o: TrmTEK4025.c Trm.h display.h
TrmTERM.o: TrmTERM.c Trm.h keyboard.h config.h
TrmGT40.o: TrmGT40.c Trm.h
TrmBitG.o: TrmBitG.c Trm.h
TrmGigi.o: TrmGigi.c Trm.h
TrmHP.o: TrmHP.c Trm.h
TrmVT100.o: TrmVT100.c Trm.h
abbrev.o: abbrev.c abbrev.h buffer.h window.h keyboard.h syntax.h macros.h mlisp.h
abspath.o: abspath.c config.h keyboard.h mlisp.h
arithmetic.o: arithmetic.c mlisp.h keyboard.h buffer.h window.h
buffer.o: buffer.c config.h buffer.h syntax.h abbrev.h keyboard.h mchan.h mlisp.h
casefiddle.o: casefiddle.c buffer.h window.h keyboard.h syntax.h
columns.o: columns.c buffer.h window.h
dbmanager.o: dbmanager.c ndbm.h buffer.h window.h keyboard.h
display.o: display.c display.h Trm.h mlisp.h
dsp.o: dsp.c buffer.h display.h window.h buffer.h config.h keyboard.h Trm.h mlisp.h
emacs.o: emacs.c buffer.h keyboard.h macros.h keyboard.h config.h mlisp.h
errlog.o: errlog.c buffer.h window.h keyboard.h search.h
fileio.o: fileio.c keyboard.h window.h buffer.h config.h mlisp.h
keyboard.o: keyboard.c keyboard.h window.h buffer.h config.h mchan.h mlisp.h
lispfuncs.o: lispfuncs.c buffer.h window.h macros.h mlisp.h config.h keyboard.h
cvllispfuncs.o: lispfuncs.c buffer.h window.h macros.h mlisp.h config.h keyboard.h
$(CC) '-DSystemName="cvl"' $(CFLAGS) -c -S lispfuncs.c
as -o cvllispfuncs.o lispfuncs.s
@rm -f lispfuncs.s
eelispfuncs.o: lispfuncs.c buffer.h window.h macros.h mlisp.h config.h keyboard.h
$(CC) '-DSystemName="eneevax"' '-DPATH_LOADSEARCH=":/p/emacs/maclib:/p/emacs/loclib"' $(CFLAGS) -c -S lispfuncs.c
as -o eelispfuncs.o lispfuncs.s
@rm -f lispfuncs.s
macros.o: macros.c keyboard.h macros.h buffer.h mlisp.h
mchan.o: mchan.c config.h window.h keyboard.h buffer.h mlisp.h macros.h mchan.h
pchan.o: pchan.c config.h window.h keyboard.h buffer.h mlisp.h macros.h mchan.h
schan.o: schan.c config.h window.h keyboard.h buffer.h mlisp.h macros.h mchan.h
filecomp.o: buffer.h window.h keyboard.h mlisp.h
metacoms.o: metacoms.c buffer.h window.h keyboard.h syntax.h syntax.h mlisp.h
minibuf.o: minibuf.c keyboard.h window.h buffer.h mlisp.h
mlisp.o: mlisp.c keyboard.h mlisp.h buffer.h window.h macros.h config.h search.h Trm.h
options.o: options.c buffer.h window.h macros.h config.h mlisp.h keyboard.h
search.o: search.c keyboard.h window.h buffer.h syntax.h mlisp.h search.h
simplecoms.o: simplecoms.c keyboard.h window.h buffer.h mlisp.h macros.h
subproc.o: subproc.c keyboard.h window.h buffer.h mlisp.h
syntax.o: syntax.c syntax.h buffer.h window.h keyboard.h
undo.o: undo.c undo.h buffer.h window.h keyboard.h
window.o: config.h window.c buffer.h display.h window.h Trm.h mlisp.h
windowman.o: windowman.c buffer.h window.h keyboard.h mlisp.h
2malloc.o: 2malloc.c buffer.h keyboard.h window.h
sindex.o: sindex.c
cc -c -O sindex.c
grep: grep.c
cc grep.c -o grep
dbadd: ndbm.h ndbm.o dbadd.o
cc -o dbadd dbadd.o ndbm.o ${LIBES}
dbprint: ndbm.h ndbm.o dbprint.o
cc -o dbprint dbprint.o ndbm.o ${LIBES}
dblist: ndbm.h ndbm.o dblist.o
cc -o dblist dblist.o ndbm.o ${LIBES}
ndbm.o : ndbm.h ndbm.c
filesort: filesort.c sindex.o
cc -g filesort.c sindex.o -o filesort ${LIBES}
install:
@echo "Don't use install for normal installation; use 'make sys'"
@echo "(Use 'really-install' to install all)"
really-install: all # mv -f temacs $(EMDESTDIR)/emacs
cp makemail $(DESTDIR)
cp collectmail $(DESTDIR)
cp loadst $(DESTDIR)
chmod u+s $(DESTDIR)/loadst
cp newloadst $(DESTDIR)
chmod u+s $(DESTDIR)/newloadst
# cp grep $(DESTDIR)
# cp dbadd $(DESTDIR)
# cp dbprint $(DESTDIR)
# cp dblist $(DESTDIR)
# cp loadst $(DESTDIR)
# cp dbcreate $(DESTDIR)
clean:
rm -f ${obj} temacs pemacs cvltemacs cvllispfuncs.o
sys: temacs cvlsys eetemacs # Sets up with sticky bit & all
@-size temacs /usr/local/emacs
-chmod 755 /usr/local/emacs
-/usr/local/emacs -q -eexit-emacs </dev/null >/dev/null
rm -f /usr/local/emacs
mv temacs /usr/local/emacs
# strip /usr/local/emacs
chmod 1755 /usr/local/emacs
cvlsys: cvltemacs
# strip cvltemacs
uucp -c cvltemacs cvl!~uucp/emacs
mail -s 'A new emacs is in ~uucp/emacs' cvl!staff </dev/null
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 664 makefile
/bin/echo -n ' '; /bin/ls -ld makefile
fi
/bin/echo 'Extracting mchan.h'
sed 's/^X//' <<'//go.sysin dd *' >mchan.h
#define debug(x) fprintf(stderr,"x:%d\n",x);fflush(stderr)
#define debugh(x) fprintf(stderr,"x");fflush(stderr)
#ifdef ECHOKEYS
#define mpx_getc(p,t) (--(p)->ch_count>=0? *(p)->ch_ptr++&0377:fill_chan(p,t))
#else
#define mpx_getc(p) (--(p)->ch_count>=0? *(p)->ch_ptr++&0377:fill_chan(p))
#endif
#define mpxin (&stdin_chan)
#ifdef MPXcode
#define index_t unsigned short /* Was `int' but is `short' in <sys/mx.h> */
#else
#define index_t int /* Is `int' again for 4.1a */
#endif
#define STOPPED (1<<0)
#define RUNNING (1<<1)
#define EXITED (1<<2)
#define SIGNALED (1<<3)
#define COREDUMPED (1<<4)
#define CHANGED (1<<6)
#define active_process(x) ((x!=NULL)&& (x->p_flag&(RUNNING|STOPPED)))
extern int errno;
#ifdef MPXcode
X/* mpx_msg is the structure of a mpx control message read from the mpx file
*/
struct mpx_msg {
short mpx_code, mpx_arg;
struct sgttyb mpx_ioctl;
};
#else
struct wh {
short index, count, ccount;
char *data;
};
#endif
X/* Structure records pertinent information about channels open on the mpx file
There is one channel associated with each process.
*/
struct channel_blk
{index_t ch_index;
struct wh ch_outrec; /* Output record */
char *ch_ptr; /* Pointer to next input character */
short ch_count; /* Count of characters remaining in buffer */
struct buffer *ch_buffer; /* Process is bound to this buffer */
struct BoundName *ch_proc; /* Procedure which gets called on output */
struct BoundName *ch_sent; /* Procedure which gets called on exit */
};
X/* Standard input is connected to the multiplexed file using a channel
described by stdin_chan.
*/
extern struct channel_blk stdin_chan;
X/* Structure for information needed for each sub process started */
struct process_blk {
struct process_blk *next_process; /* link to next process */
char *p_name; /* command that started process */
short p_pid; /* process id */
short p_gid; /* process pgrp */
char p_flag; /* RUNNING, STOPPED, etc */
char p_reason; /* signal causing p_flag */
struct channel_blk p_chan; /* process i/o connected to channel */
};
struct process_blk *process_list, /* all existing processes */
*current_process; /* the one that we're currently
dealing with */
int sflag; /* the -s command line switch (enables the
share-emacs facility) */
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 664 mchan.h
/bin/echo -n ' '; /bin/ls -ld mchan.h
fi
/bin/echo 'Extracting schan.c'
sed 's/^X//' <<'//go.sysin dd *' >schan.c
X/* These procedures hope to give EMACS a facility for dealing with multiple
processes in a reasonable way */
X/* This file used to be known as mchan.c - it's now called schan.c.
It contains the general multiple process handling routines.
Specific routines, which deal with low-level MPXio or PTYio (depending
on the setting of MPXcode) can be found in mchan.c or pchan.c
(respectively).
* Among the things found in this version
- support for csh
- unexpected processes
- process sentinels
* The original MPXio code is (c) 1981 Carl Ebeling
* The changes for MPXio to handle this were made by Chris Torek
<Chris at Umcp-CS>
* The original changes to convert to PTYio are (c) 1982 William N. Joy and
Regents of UC
* Their code didn't quite work right, so Spencer Thomas
<UTAH-GR.thomas at Utah-Cs> fixed things up
* Marshall Rose <MRose at UCI> made some more changes for 4.1a, and finally
split mchan.c into three files.
* Changes for 4.1c by Chris Kent at DecWRL, incorporated by Spencer Thomas.
*/
X/* Both mchan and pchan contain these routines used by schan (and others):
create_process - starts a subprocess (on a PTY or MPX channel)
fill_chan - read from subprocesses
kill_processes - terminate all subprocesses without predjudice
sig_process - send a signal to a subprocess (or process group)
EOTProcess - send an EOT to a process group
PID - return the process-id of a subprocess (or process group)
InitProcesses - initialize for subprocess handling
QuitMPX - clean-up after subprocess handling
SuspendMPX - temporarily stop subprocess handling
ResumeMPX - resume subprocess handling
In addition, mchan and pchan contain some static routines for internal use.
*/
#include "config.h"
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <wait.h>
#include <sgtty.h>
#ifdef MPXcode
#include <sys/mx.h>
#endif MPXcode
#include "window.h"
#include "keyboard.h"
#include "buffer.h"
#include "mlisp.h"
#include "macros.h"
#include "mchan.h"
#ifdef subprocesses
#define ChunkSize 500 /* amount to truncate when buffer overflows */
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 */
static ProcessBufferSize; /* Maximum size for process buffer */
#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"
};
#endif
X/* 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;
#ifdef subprocesses
register struct process_blk *p;
extern struct process_blk *get_next_process ();
#endif
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;
}
#ifdef subprocesses
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)) {
p -> p_flag = STOPPED | CHANGED;
p -> p_reason = w.w_stopsig;
child_changed++;
}
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 ();
#endif
goto loop;
}
#ifdef subprocesses
X/* 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);
}
X/* 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;
}
X/* 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;
#if EmacsVersionNum > 263
struct buffer *oldg = Generate;
Generate = 0;
#endif EmacsVersionNum > 263
arg = (p -> p_reason & 0xffff) | (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;
#if EmacsVersionNum > 263
Generate = oldg;
#endif EmacsVersionNum > 263
}
}
#ifdef HalfBaked
sigrelse (SIGINT);
#endif
DoDsp (1);
SetBfp (old);
}
X/* Output has been recieved from a process on "chan" and should be stuffed in
the correct buffer */
X/* 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;
int old_buffer_is_visible = wn_cur->w_buf==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 && old_buffer_is_visible)
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 */
}
X/* 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);
}
#ifdef DumpableEmacs
X/* Flush all processes, called after kill_processes by dump-emacs */
X/* Here since emacs.c doesnt want to know about this gunk */
flush_all_processes () {
register struct process_blk *p;
for (p = process_list; p; p = process_list) {
process_list = p -> next_process;
free (p);
}
}
#endif DumpableEmacs
X/* 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;
}
X/* Start up a new process by creating the process block and initializing
things correctly */
start_process (com, buf, proc)
register char *com,
*buf;
#if EmacsVersionNum > 263
struct BoundName *proc;
#endif EmacsVersionNum > 263
{
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;
#if EmacsVersionNum > 263
current_process -> p_chan.ch_proc = proc;
#else
current_process -> p_chan.ch_proc = (proc < 0 ? NULL : MacBodies[proc]);
#endif EmacsVersionNum > 263
current_process -> p_chan.ch_sent = NULL;
sigrelse (SIGCHLD);
return 0;
}
X/* 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;
#if EmacsVersionNum > 263
start_process (com, buf, NULL);
#else
start_process (com, buf, -1);
#endif EmacsVersionNum > 263
return 0; /* ACT 8-Sep-1982 */
}
X/* 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;
#if EmacsVersionNum > 263
struct BoundName *proc;
#else
int proc;
#endif EmacsVersionNum > 263
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);
#if EmacsVersionNum > 263
proc = ProcArg ("On-output procedure: ");
if (proc == NothingNode)
proc = 0;
#else
proc = getword (MacNames, "On-output procedure: ");
#endif EmacsVersionNum > 263
start_process (com, bufname[0] ? bufname : NULL, proc);
return 0; /* ACT 8-Sep-1982 */
}
X/* Set the UnexpectedProc pointer */
static
SetUnexpectedProc () {
#if EmacsVersionNum > 263
UnexpectedProc = ProcArg ("unexpected-process-filter: ");
if (UnexpectedProc == NothingNode)
UnexpectedProc = 0;
#else
register proc = getword (MacNames, "unexpected-process-filter: ");
UnexpectedProc = proc < 0 ? NULL : MacBodies[proc];
#endif EmacsVersionNum > 263
}
X/* 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]);
}
X/* 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;
#if EmacsVersionNum > 263
register struct BoundName *proc;
#else
register int proc;
#endif EmacsVersionNum > 263
if ((process = GetBufProc ()) == NULL) {
error ("Not a Process");
return 0;
}
#if EmacsVersionNum > 263
proc = ProcArg ("On-output procedure: ");
process -> p_chan.ch_proc = proc == NothingNode ? 0 : proc;
#else
proc = getword(MacNames, "On-output procedure: ");
process -> p_chan.ch_proc = (proc < 0 ? NULL : MacBodies[proc]);
#endif EmacsVersionNum > 263
return(0);
}
X/* 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 */
}
X/* 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;
#if EmacsVersionNum > 263
register struct BoundName *proc;
#else
register int proc;
#endif EmacsVersionNum > 263
if ((process = GetBufProc ()) == NULL) {
error ("Not a Process");
return 0;
}
#if EmacsVersionNum > 263
proc = ProcArg ("On-exit procedure: ");
process -> p_chan.ch_sent = proc == NothingNode ? 0 : proc;
#else
proc = getword(MacNames, "On-exit procedure: ");
process -> p_chan.ch_sent = (proc < 0 ? NULL : MacBodies[proc]);
#endif EmacsVersionNum > 263
return(0);
}
static
ResetSentinel () {
register struct process_blk *process;
if ((process = GetBufProc ()) == NULL) {
error ("Not a Process");
return 0;
}
process -> p_chan.ch_sent = NULL;
return 0;
}
static
ProcessSentinelName () {
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_sent
? process -> p_chan.ch_sent -> b_name : "";
MLvalue -> exp_int = strlen (name);
MLvalue -> exp_v.v_string = name;
return 0;
}
static
SetUnexpectedSent() {
#if EmacsVersionNum > 263
UnexpectedSent = ProcArg ("unexpected-process-sentinel: ");
if (UnexpectedSent == NothingNode)
UnexpectedSent = 0;
#else
register proc = getword (MacNames, "unexpected-process-sentinel: ");
UnexpectedSent = proc < 0 ? NULL : MacBodies[proc];
#endif EmacsVersionNum > 263
}
X/* List the current processes. After listing stopped or exited processes,
flush them from the process list. */
ListProcesses () {
register struct buffer *old = bf_cur;
register struct process_blk *p;
char line[150], tline[20];
SetBfn ("Process list");
if (interactive)
WindowOn (bf_cur);
EraseBf (bf_cur);
InsStr ("\
Buffer Status Command\n\
------ ------ -------\n");
sighold (SIGCHLD);
for (p = process_list; p != NULL; p = p -> next_process) {
sprintfl (line, sizeof line, "%-24s", p -> p_chan.ch_buffer -> b_name);
InsStr (line);
switch (p -> p_flag & (STOPPED | RUNNING | EXITED | SIGNALED)) {
case STOPPED:
sprintfl (line, sizeof line, "%-17s", "Stopped");
break;
case RUNNING:
sprintfl (line, sizeof line, "%-17s", "Running");
break;
case EXITED:
sprintfl (tline, sizeof tline,
p -> p_reason ? "Exit %d" : "Exited", p -> p_reason);
sprintf (line, "%-17s", tline);
flush_process (p);
break;
case SIGNALED:
sprintfl (tline, sizeof tline, "%s%s",
SIG_names[p -> p_reason],
p -> p_flag & COREDUMPED ? " (core dumped)" : "");
sprintf (line, "%-17s", tline);
flush_process (p);
break;
default:
sprintf (line, "0x%x\n", p -> p_flag);
InsStr (line);
continue;
}
InsStr (line);
sprintfl (line, sizeof line, " %-32s\n", p -> p_name);
InsStr (line);
}
sigrelse (SIGCHLD);
bf_modified = 0;
SetBfp (old);
WindowOn (bf_cur);
return 0;
}
X/* Take input from mark to dot and feed to the subprocess */
RegionToProcess () {
register left,
right;
register struct process_blk *process;
register struct wh *output;
if ((process = GetBufProc ()) == NULL) {
error ("Not a Process");
return 0;
}
if (bf_cur -> b_mark == 0) {
error ("Mark not set");
return 0;
}
left = ToMark (bf_cur -> b_mark);
if (left <= dot)
right = dot;
else {
right = left;
left = dot;
}
if (right - left <= 0) {
error ("Region is null");
return 0;
}
if (left < bf_s1 && right >= bf_s1)
GapTo (left);
output = &process -> p_chan.ch_outrec;
if (output -> count || output -> ccount)
error ("Overwriting on blocked channel");
output -> index = process -> p_chan.ch_index;
output -> ccount = 0;
output -> count = right - left;
output -> data = &CharAt (left);
send_chan (process);
return 0;
}
X/* Send a string to the process as input */
StringToProcess () {
register char *input_string;
register struct process_blk *process;
register struct wh *output;
if ((process = GetBufProc()) == NULL) {
error ("Not a Process");
return 0;
}
input_string = getstr("String: ");
output = &process -> p_chan.ch_outrec;
if (output -> count || output -> ccount)
error("Overwriting on blocked channel");
output -> index = process -> p_chan.ch_index;
output -> ccount = 0;
output -> count = strlen(input_string);
if (output -> count <= 0)
error("Null string");
output -> data = input_string;
send_chan (process);
return 0;
}
X/* Get the current output which has been thrown at us and send it
to the user as a string; this is only allowed if MPX_chan is non-null
indicating that this has been indirectly called from stuff_buffer. */
ProcessOutput () {
if (MPX_chan == NULL) {
error ("process-output can only be called from filter");
return 0;
}
MLvalue -> exp_type = IsString;
MLvalue -> exp_release = 1;
MLvalue -> exp_int = MPX_chan -> ch_count;
MLvalue -> exp_v.v_string = (char *) malloc (MLvalue -> exp_int + 1);
cpyn (MLvalue -> exp_v.v_string, MPX_chan -> ch_ptr,
MLvalue -> exp_int);
MLvalue -> exp_v.v_string[MLvalue -> exp_int] = '\0';
return 0;
}
IntProcess () {
return (sig_process (SIGINT, 0));
}
IntPLeader () {
return (sig_process (SIGINT, 1));
}
QuitProcess () {
return (sig_process (SIGQUIT, 0));
}
QuitPLeader () {
return (sig_process (SIGQUIT, 1));
}
KillProcess () {
return (sig_process (SIGKILL, 0));
}
KillPLeader () {
return (sig_process (SIGKILL, 1));
}
StopProcess () {
return (sig_process (SIGTSTP, 0));
}
StopPLeader () {
return (sig_process (SIGTSTP, 1));
}
ContProcess () {
return (sig_process (SIGCONT, 0));
}
ContPLeader () {
return (sig_process (SIGCONT, 1));
}
SignalToProcess () {
return SignalToProcOrLeader (0);
}
SignalToPLeader () {
return SignalToProcOrLeader (1);
}
SignalToProcOrLeader (leader) {
register char *s = getnbstr ("Signal: ");
register i;
if (!s || !*s) return 0;
if (*s >= '0' && *s <= '9')
return sig_process (atoi (s), leader);
for (i = 0; i < sizeof KillNames/sizeof *KillNames; i++)
if (strcmp (KillNames[i], s) == 0)
return sig_process (i, leader);
error ("\"%s\" is not a signal name", s);
return 0;
}
X/* Some useful functions on the process */
StrFunc (CurrentProcess,
(current_process ? current_process -> p_chan.ch_buffer -> b_name : ""));
X/* Return the name of the currently active process: it is defined as the name
of the current buffer if is attached to an active process. */
ActiveProcess () {
register struct process_blk *p;
for (p = process_list; p != NULL; p = p -> next_process)
if (active_process (p) && (p -> p_chan.ch_buffer == bf_cur))
break;
if (p == NULL)
p = current_process;
MLvalue -> exp_type = IsString;
MLvalue -> exp_release = 0;
if (p == NULL) {
MLvalue -> exp_int = 0;
MLvalue -> exp_v.v_string = NULL;
}
else {
MLvalue -> exp_int = strlen (p -> p_chan.ch_buffer -> b_name);
MLvalue -> exp_v.v_string = p -> p_chan.ch_buffer -> b_name;
}
return 0;
}
X/* Change the current-process to the one indicated */
ChangeCurrentProcess () {
register struct process_blk *process = GetBufProc ();
if (process == NULL) {
error ("Not a process");
return 0;
}
current_process = process;
return 0;
}
X/* Return the process' status:
-1 - not an active process
0 - a stopped process
1 - a running process
*/
X/* It's tempting to make this call GetBufProc() - but do not ... */
ProcessStatus () {
register char *name = getstr ("Process: ");
register struct process_blk *process = find_process (name);
MLvalue -> exp_type = IsInteger;
if (process == NULL)
MLvalue -> exp_int = -1;
else
if (process -> p_flag & RUNNING)
MLvalue -> exp_int = 1;
else
MLvalue -> exp_int = 0;
return 0;
}
X/* Get the process id */
ProcessID () {
return PID (0);
}
X/* Get the process leader id */
PLeaderID () {
return PID (1);
}
X/* Get input from a subprocess (or the tty) and process it.
* Tty input is just buffered until requested.
*/
static AwaitProcessInput () /* just poll for input */
{
#ifdef ECHOKEYS
fill_chan(NULL, 0);
#else
fill_chan(NULL);
#endif
}
#endif subprocesses
X/* Initialize things for multiple process handling. */
InitMpx () {
extern child_sig ();
#ifdef subprocesses
extern EOTProcess ();
#endif
#ifdef ce
err_file = fopen ("/tmp/emacs.mxdebug", "a");
if (err_file == NULL) {
unlink ("/tmp/emacs.mxdebug");
err_file = fopen ("/tmp/emacs.mxdebug", "a");
}
chmod ("/tmp/emacs.mxdebug", 0666);
setbuf (err_file, NULL);
err_id = getuid ();
#endif
InitProcesses ();
sigset (SIGCHLD, child_sig);
#ifdef subprocesses
#ifdef DumpableEmacs
if (!Once)
#endif
{
DefStrVar ("MPX-process", "");
MPX_process = NextInitVarDesc[-1];
ProcessBufferSize = 10000;/* # of chars in buffer before truncating */
DefIntVar ("process-buffer-size", &ProcessBufferSize);
PopUpUnexpected = 1;
DefIntVar ("pop-up-process-windows", &PopUpUnexpected);
EmacsShare = 1;
DefIntVar ("emacs-share", &EmacsShare);
defproc (StartProcess, "start-process");
defproc (StartFilteredProcess, "start-filtered-process");
defproc (InsertFilter, "insert-filter");
defproc (ResetFilter, "reset-filter");
defproc (ProcessFilterName, "process-filter-name");
defproc (RegionToProcess, "region-to-process");
defproc (StringToProcess, "string-to-process");
defproc (IntProcess, "int-process");
defproc (QuitProcess, "quit-process");
defproc (KillProcess, "kill-process");
defproc (StopProcess, "stop-process");
defproc (ContProcess, "continue-process");
defproc (IntPLeader, "int-process-leader");
defproc (QuitPLeader, "quit-process-leader");
defproc (KillPLeader, "kill-process-leader");
defproc (StopPLeader, "stop-process-leader");
defproc (ContPLeader, "continue-process-leader");
defproc (SignalToProcess, "signal-to-process");
defproc (SignalToPLeader, "signal-to-process-leader");
defproc (EOTProcess, "eot-process");
defproc (CurrentProcess, "current-process");
defproc (ProcessStatus, "process-status");
defproc (ChangeCurrentProcess, "change-current-process");
defproc (ActiveProcess, "active-process");
defproc (ProcessID, "process-id");
defproc (PLeaderID, "process-leader-id");
defproc (ProcessOutput, "process-output");
defproc (ListProcesses, "list-processes");
defproc (SetUnexpectedProc, "unexpected-process-filter");
defproc (InsertSentinel, "insert-sentinel");
defproc (ResetSentinel, "reset-sentinel");
defproc (ProcessSentinelName, "process-sentinel-name");
defproc (SetUnexpectedSent, "unexpected-process-sentinel");
defproc (AwaitProcessInput, "await-process-input");
}
#endif
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 664 schan.c
/bin/echo -n ' '; /bin/ls -ld schan.c
fi
--
In-Real-Life: Chris Torek, Univ of MD Comp Sci
UUCP: {seismo,allegra,brl-bmd}!umcp-cs!chris
CSNet: chris at umcp-cs ARPA: chris.umcp-cs at UDel-Relay
More information about the Comp.sources.unix
mailing list