v08i015: A Micro-Emacs variant that resembles GNU Emacs
sources-request at mirror.UUCP
sources-request at mirror.UUCP
Wed Jan 28 04:26:04 AEST 1987
Submitted by: Bob Larson <seismo!usc-oberon!blarson>
Mod.sources: Volume 8, Issue 15
Archive-name: micrognu/Part08
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
# sys/eunice/Makefile
# sys/eunice/fileio.c
# sys/eunice/readme
# sys/eunice/spawn.c
# sys/eunice/sysdef.h
# sys/eunice/ttyio.c
# sys/vms/aaareadme.1st
# sys/vms/bcopy.mar
# sys/vms/ccom.com
# sys/vms/make.com
# sys/vms/mg.com
# sys/vms/mglink.com
# sys/vms/mgmailedit.com
# sys/vms/emacs.opt
# sys/vms/fileio.c
# sys/vms/spawn.c
# sys/vms/trnlnm.c
# sys/vms/ttyio.c
# sys/vms/sysdef.h
# This archive created: Sat Nov 15 15:40:17 1986
export PATH; PATH=/bin:$PATH
if test ! -d sys/eunice
then
mkdir sys/eunice
fi
if test ! -d sys/vms
then
mkdir sys/vms
fi
if test ! -d sys/vms/termcap
then
mkdir sys/vms/termcap
fi
if test -f 'sys/eunice/Makefile'
then
echo shar: will not over-write existing file "'sys/eunice/Makefile'"
else
cat << \SHAR_EOF > 'sys/eunice/Makefile'
# Makefile for MicroEMACS, under Eunice
SYS =eunice
TTY =termcap
LIBS = -ltermcap
# CDEFS gets defines, and gets passed to lint. CFLAGS gets flags, and doesn't
# get passed to lint.
CDEFS = -Isys/$(SYS)/ -Itty/$(TTY)/ -DDO_METAKEY -DSTARTUP
CFLAGS = -g $(CDEFS)
OBJ = basic.o buffer.o cinfo.o display.o echo.o extend.o file.o kbd.o \
line.o main.o match.o random.o region.o search.o symbol.o version.o \
window.o paragraph.o prefix.o word.o \
fileio.o spawn.o ttyio.o tty.o ttykbd.o
OSRCS = fileio.c spawn.c ttyio.c tty.c ttykbd.c
SRCS = basic.c buffer.c cinfo.c display.c echo.c extend.c file.c kbd.c \
line.c main.c match.c random.c region.c search.c symbol.c version.c \
window.c word.c paragraph.c prefix.c
INCS = def.h
mg: $(OBJ) $(XOBJ)
cc $(CFLAGS) -o mg $(OBJ) $(LIBS)
rm -f $(OSRCS)
# the v arg to lint turns off all the complaints about args f, n & k.
# It's a good idea to take that out and rerun make lint after getting
# a clean lint, just to verify that f, n & k are the ONLY unused args.
lint: $(SRCS) $(OSRCS)
lint -ahb $(CDEFS) $(SRCS) $(OSRCS)
clean: rm -f *.o $(OSRCS)
$(OBJ): def.h sys/$(SYS)/sysdef.h tty/$(TTY)/ttydef.h
fileio.c: sys/$(SYS)/fileio.c
cp sys/$(SYS)/fileio.c .
spawn.c: sys/$(SYS)/spawn.c
cp sys/$(SYS)/spawn.c .
tty.c: tty/$(TTY)/tty.c
cp tty/$(TTY)/tty.c .
ttyio.c: sys/$(SYS)/ttyio.c
cp sys/$(SYS)/ttyio.c .
ttykbd.c: tty/$(TTY)/ttykbd.c
cp tty/$(TTY)/ttykbd.c .
SHAR_EOF
fi # end of overwriting check
if test -f 'sys/eunice/fileio.c'
then
echo shar: will not over-write existing file "'sys/eunice/fileio.c'"
else
cat << \SHAR_EOF > 'sys/eunice/fileio.c'
/*
* Eunice BSD 4.2 file I/O
*/
#include "def.h"
#ifndef F_OK
#define F_OK FRDONLY
#endif
static FILE *ffp;
extern char *getenv();
/*
* handle C-shell style names
*/
static char *bsd(fn, buf, bufsiz) char *fn, *buf; int bufsiz;
{
if (*fn != '~')
return (fn);
else { /* C-shell $HOME-relative names */
strncpy(buf, getenv("HOME"), bufsiz);
strncat(buf, fn + 1, bufsiz);
return (buf);
}
}
/*
* Open a file for reading.
*/
ffropen(fn) char *fn; {
char buf[NFILEN];
fn = bsd(fn, buf, sizeof(buf));
if ((ffp=fopen(fn, "r")) == NULL)
return (FIOFNF);
return (FIOSUC);
}
/*
* Open a file for writing.
* Return TRUE if all is well, and
* FALSE on error (cannot create).
*/
ffwopen(fn) char *fn; {
char buf[NFILEN];
fn = bsd(fn, buf, sizeof(buf));
if ((ffp=fopen(fn, "w")) == NULL) {
ewprintf("Cannot open file for writing");
return (FIOERR);
}
return (FIOSUC);
}
/*
* Close a file.
* Should look at the status.
*/
ffclose() {
(VOID) fclose(ffp);
return (FIOSUC);
}
/*
* Write a line to the already
* opened file. The "buf" points to the
* buffer, and the "nbuf" is its length, less
* the free newline. Return the status.
* Check only at the newline.
*/
ffputline(buf, nbuf) register char buf[]; {
register int i;
/* What's with putc? */
for (i=0; i<nbuf; ++i)
putc(buf[i]&0xFF, ffp);
putc('\n', ffp);
if (ferror(ffp) != FALSE) {
ewprintf("Write I/O error");
return (FIOERR);
}
return (FIOSUC);
}
/*
* Read a line from a file, and store the bytes
* in the supplied buffer. Stop on end of file or end of
* line. Don't get upset by files that don't have an end of
* line on the last line; this seem to be common on CP/M-86 and
* MS-DOS (the suspected culprit is VAX/VMS kermit, but this
* has not been confirmed. If this is sufficiently researched
* it may be possible to pull this kludge). Delete any CR
* followed by an LF. This is mainly for runoff documents,
* both on VMS and on Ultrix (they get copied over from
* VMS systems with DECnet).
*/
ffgetline(buf, nbuf) register char buf[]; {
register int c;
register int i;
i = 0;
for (;;) {
c = getc(ffp);
if (c == '\r') { /* Delete any non-stray */
c = getc(ffp); /* carriage returns. */
if (c != '\n') {
if (i >= nbuf-1) {
ewprintf("File has long line");
return (FIOERR);
}
buf[i++] = '\r';
}
}
if (c==EOF || c=='\n') /* End of line. */
break;
if (i >= nbuf-1) {
ewprintf("File has long line");
return (FIOERR);
}
buf[i++] = c;
}
if (c == EOF) { /* End of file. */
if (ferror(ffp) != FALSE) {
ewprintf("File read error");
return (FIOERR);
}
if (i == 0) /* Don't get upset if */
return (FIOEOF); /* no newline at EOF. */
}
buf[i] = 0;
return (FIOSUC);
}
#if BACKUP
/*
* Rename the file "fname" into a backup
* copy. On Unix the backup has the same name as the
* original file, with a "~" on the end; this seems to
* be newest of the new-speak. The error handling is
* all in "file.c". The "unlink" is perhaps not the
* right thing here; I don't care that much as
* I don't enable backups myself.
*/
fbackupfile(fn) char *fn; {
register char *nname;
char *malloc();
char buf[NFILEN];
fn = bsd(fn, buf, sizeof(buf));
if ((nname=malloc(strlen(fn)+1+1)) == NULL) {
ewprintf("Can't get %d bytes", strlen(fname) + 1);
return (ABORT);
}
(void) strcpy(nname, fn);
(void) strcat(nname, "~");
(void) unlink(nname); /* Ignore errors. */
if (rename(fname, nname) < 0) {
free(nname);
return (FALSE);
}
free(nname);
return (TRUE);
}
#endif
/*
* The string "fn" is a file name.
* Perform any required case adjustments. All sustems
* we deal with so far have case insensitive file systems.
* We zap everything to lower case. The problem we are trying
* to solve is getting 2 buffers holding the same file if
* you visit one of them with the "caps lock" key down.
* On UNIX file names are dual case, so we leave
* everything alone.
*/
/*ARGSUSED*/
adjustcase(fn) register char *fn; {
#if 0
register int c;
while ((c = *fn) != 0) {
if (c>='A' && c<='Z')
*fn = c + 'a' - 'A';
++fn;
}
#endif
}
#ifdef STARTUP
#include <sys/file.h>
/*
* find the users startup file, and return it's name. Check for
* $HOME/.mg then for $HOME/.emacs, then give up.
*/
char *
startupfile() {
register char *file;
static char home[NFILEN];
char *getenv();
if ((file = getenv("HOME")) == NULL) return NULL;
if (strlen(file)+7 >= NFILEN - 1) return NULL;
(VOID) strcpy(home, file);
file = &(home[strlen(home)]);
*file++ = '/';
(VOID) strcpy(file, ".mg");
if (access(home, F_OK ) == 0) return home;
(VOID) strcpy(file, ".emacs");
if (access(home, F_OK) == 0) return home;
return NULL;
}
#endif
SHAR_EOF
fi # end of overwriting check
if test -f 'sys/eunice/readme'
then
echo shar: will not over-write existing file "'sys/eunice/readme'"
else
cat << \SHAR_EOF > 'sys/eunice/readme'
This directory contains sources that allow MicroEmacs to be compiled
and linked using Eunice cc. Although I am the de facto Eunice hacker
at the site I work for, I don't have enough experience with it to
understand why it crashes for me when I attempt to run it under the
C shell. If I give the command
$ MG :== $dev:[dir]MG. MG
and invoke it from DCL, it works fine. If you find out what's wrong
(probably something simple), let me know.
If you have the VAX C compiler, you might be better off using the native
VMS terminal/system modules, to avoid the overhead involved in running Eunice.
Mic Kaczmarczik
...!ihnp4!seismo!ut-sally!ut-ngp!mic
ccep001 at utadnx.bitnet
mic at ngp.utexas.edu
SHAR_EOF
fi # end of overwriting check
if test -f 'sys/eunice/spawn.c'
then
echo shar: will not over-write existing file "'sys/eunice/spawn.c'"
else
cat << \SHAR_EOF > 'sys/eunice/spawn.c'
/*
* Spawn. New version, which
* interracts with the job control stuff
* in the 4.X BSD C shell.
* Last edit: Wed Aug 27 11:16:07 PDT 1986
* By: rtech!daveb, to use stop for ksh.
*/
#include "def.h"
#include <sgtty.h>
#include <signal.h>
char *shellp = NULL; /* Saved "SHELL" name. */
extern struct sgttyb oldtty; /* There really should be a */
extern struct sgttyb newtty; /* nicer way of doing this, so */
extern struct sgttyb oldtchars; /* spawn does not need to know */
extern struct sgttyb newtchars; /* about the insides of the */
extern struct sgttyb oldltchars; /* terminal I/O code. */
extern struct sgttyb newltchars;
extern char *getenv();
/*
* This code does a one of 2 different
* things, depending on what version of the shell
* you are using. If you are using the C shell, which
* implies that you are using job control, then MicroEMACS
* moves the cursor to a nice place and sends itself a
* stop signal. If you are using the Bourne shell it runs
* a subshell using fork/exec. Bound to "C-C", and used
* as a subcommand by "C-Z".
*
* Daveb -- changed sense of test so that we only spawn if you
* are explicitly using /bin/sh. This makes it stop
* work with the ksh.
*/
/*ARGSUSED*/
spawncli(f, n, k) {
register int pid, wpid, (*oqsig)(), (*oisig)(), omask;
int status;
if (shellp == NULL) {
shellp = getenv("SHELL");
if (shellp == NULL)
shellp = getenv("shell");
if (shellp == NULL)
shellp = "/bin/sh"; /* Safer. */
}
ttcolor(CTEXT);
ttnowindow();
if (strcmp(shellp, "/bin/csh") == 0) {
if (epresf != FALSE) {
ttmove(nrow-1, 0);
tteeol();
epresf = FALSE;
} /* Csh types a "\n" */
ttmove(nrow-2, 0); /* before "Stopped". */
} else {
ttmove(nrow-1, 0);
if (epresf != FALSE) {
tteeol();
epresf = FALSE;
}
}
ttflush();
if (ioctl(0, TIOCSLTC, (char *) &oldltchars) < 0
|| ioctl(0, TIOCSETC, (char *) &oldtchars) < 0
|| ioctl(0, TIOCSETP, (char *) &oldtty) < 0) {
ewprintf("IOCTL #1 to terminal failed");
return (FALSE);
}
if (strcmp(shellp, "/bin/sh") != 0) { /* C shell, ksh */
#ifdef BSD43
omask = sigsetmask(0);
#endif
(void) kill(0, SIGTSTP);
setttysize() ;
#ifdef BSD43
(void) sigsetmask(omask);
#endif
} else { /* Bourne shell. */
oqsig = signal(SIGQUIT, SIG_IGN);
oisig = signal(SIGINT, SIG_IGN);
if ((pid=fork()) < 0) {
(void) signal(SIGQUIT, oqsig);
(void) signal(SIGINT, oisig);
ewprintf("Failed to create process");
return (FALSE);
}
if (pid == 0) {
execl(shellp, "sh", "-i", NULL);
_exit(0); /* Should do better! */
}
while ((wpid=wait(&status))>=0 && wpid!=pid)
;
(void) signal(SIGQUIT, oqsig);
(void) signal(SIGINT, oisig);
}
sgarbf = TRUE; /* Force repaint. */
if (ioctl(0, TIOCSETP, (char *) &newtty) < 0
|| ioctl(0, TIOCSETC, (char *) &newtchars) < 0
|| ioctl(0, TIOCSLTC, (char *) &newltchars) < 0) {
ewprintf("IOCTL #2 to terminal failed");
return (FALSE);
}
return (TRUE);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'sys/eunice/sysdef.h'
then
echo shar: will not over-write existing file "'sys/eunice/sysdef.h'"
else
cat << \SHAR_EOF > 'sys/eunice/sysdef.h'
/*
* Ultrix-32 system header file.
*/
#define PCC 1 /* "[]" gets an error. */
#define KBLOCK 8192 /* Kill grow. */
#define GOOD 0 /* Good exit status. */
typedef int RSIZE; /* Type for file/region sizes */
typedef short KEY; /* Type for internal keystrokes */
/*
* Macros used by the buffer name making code.
* Start at the end of the file name, scan to the left
* until BDC1 (or BDC2, if defined) is reached. The buffer
* name starts just to the right of that location, and
* stops at end of string (or at the next BDC3 character,
* if defined). BDC2 and BDC3 are mainly for VMS.
*/
#define BDC1 '/' /* Buffer names. */
SHAR_EOF
fi # end of overwriting check
if test -f 'sys/eunice/ttyio.c'
then
echo shar: will not over-write existing file "'sys/eunice/ttyio.c'"
else
cat << \SHAR_EOF > 'sys/eunice/ttyio.c'
/*
* Ultrix-32 and Unix terminal I/O.
* The functions in this file
* negotiate with the operating system for
* keyboard characters, and write characters to
* the display in a barely buffered fashion.
*/
#include "def.h"
#include <sgtty.h>
#define NOBUF 512 /* Output buffer size. */
char obuf[NOBUF]; /* Output buffer. */
int nobuf;
struct sgttyb oldtty; /* V6/V7 stty data. */
struct sgttyb newtty;
struct tchars oldtchars; /* V7 editing. */
struct tchars newtchars;
struct ltchars oldltchars; /* 4.2 BSD editing. */
struct ltchars newltchars;
#ifdef TIOCGWINSZ
struct winsize winsize; /* 4.3 BSD window sizing */
#endif
int nrow; /* Terminal size, rows. */
int ncol; /* Terminal size, columns. */
/*
* This function gets called once, to set up
* the terminal channel. On Ultrix is's tricky, since
* we want flow control, but we don't want any characters
* stolen to send signals. Use CBREAK mode, and set all
* characters but start and stop to 0xFF.
*/
ttopen() {
register char *tv_stype;
char *getenv(), *tgetstr(), tcbuf[1024], err_str[72];
if (ioctl(0, TIOCGETP, (char *) &oldtty) < 0)
panic("ttopen can't get sgtty");
newtty.sg_ospeed = oldtty.sg_ospeed;
newtty.sg_ispeed = oldtty.sg_ispeed;
newtty.sg_erase = oldtty.sg_erase;
newtty.sg_kill = oldtty.sg_kill;
newtty.sg_flags = oldtty.sg_flags;
newtty.sg_flags &= ~(ECHO|CRMOD); /* Kill echo, CR=>NL. */
#ifdef FLOWCONTROL
newtty.sg_flags |= CBREAK; /* Half-cooked mode. */
#else
newtty.sg_flags |= RAW|ANYP; /* raw mode for 8 bit path.*/
#endif
if (ioctl(0, TIOCSETP, (char *) &newtty) < 0)
panic("ttopen can't set sgtty");
if (ioctl(0, TIOCGETC, (char *) &oldtchars) < 0)
panic("ttopen can't get chars");
newtchars.t_intrc = 0xFF; /* Interrupt. */
newtchars.t_quitc = 0xFF; /* Quit. */
#if FLOWCONTROL
newtchars.t_startc = 0x11; /* ^Q, for terminal. */
newtchars.t_stopc = 0x13; /* ^S, for terminal. */
#else
newtchars.t_startc = 0xFF; /* ^Q, for terminal. */
newtchars.t_stopc = 0xFF; /* ^S, for terminal. */
#endif
newtchars.t_eofc = 0xFF;
newtchars.t_brkc = 0xFF;
if (ioctl(0, TIOCSETC, (char *) &newtchars) < 0)
panic("ttopen can't set chars");
if (ioctl(0, TIOCGLTC, (char *) &oldltchars) < 0)
panic("ttopen can't get ltchars");
newltchars.t_suspc = 0xFF; /* Suspend #1. */
newltchars.t_dsuspc = 0xFF; /* Suspend #2. */
newltchars.t_rprntc = 0xFF;
newltchars.t_flushc = 0xFF; /* Output flush. */
newltchars.t_werasc = 0xFF;
newltchars.t_lnextc = 0xFF; /* Literal next. */
if (ioctl(0, TIOCSLTC, (char *) &newltchars) < 0)
panic("ttopen can't set ltchars");
/* do this the REAL way */
if ((tv_stype = getenv("TERM")) == NULL)
{
puts("Environment variable TERM not defined!");
exit(1);
}
if((tgetent(tcbuf, tv_stype)) != 1)
{
(void) sprintf(err_str, "Unknown terminal type %s!", tv_stype);
puts(err_str);
exit(1);
}
setttysize() ;
}
/*
* This function gets called just
* before we go back home to the shell. Put all of
* the terminal parameters back.
*/
ttclose() {
ttflush();
if (ioctl(0, TIOCSLTC, (char *) &oldltchars) < 0)
panic("ttclose can't set ltchars");
if (ioctl(0, TIOCSETC, (char *) &oldtchars) < 0)
panic("ttclose can't set chars");
if (ioctl(0, TIOCSETP, (char *) &oldtty) < 0)
panic("ttclose can't set sgtty");
}
/*
* Write character to the display.
* Characters are buffered up, to make things
* a little bit more efficient.
*/
ttputc(c) {
if (nobuf >= NOBUF)
ttflush();
obuf[nobuf++] = c;
}
/*
* Flush output.
*/
ttflush() {
if (nobuf != 0) {
if (write(1, obuf, nobuf) != nobuf)
panic("ttflush write failed");
nobuf = 0;
}
}
/*
* Read character from terminal.
* All 8 bits are returned, so that you can use
* a multi-national terminal.
*/
ttgetc() {
char buf[1];
while (read(0, &buf[0], 1) != 1)
;
return (buf[0] & 0xFF);
}
/*
* set the tty size. Functionized for 43BSD.
*/
setttysize() {
#ifdef TIOCGWINSZ
if (ioctl(0, TIOCGWINSZ, (char *) &winsize) == 0) {
nrow = winsize . ws_row;
ncol = winsize . ws_col;
} else
#endif
if ((nrow=tgetnum ("li")) <= 0
|| (ncol=tgetnum ("co")) <= 0) {
nrow = 24;
ncol = 80;
}
if (nrow > NROW) /* Don't crash if the */
nrow = NROW; /* termcap entry is */
if (ncol > NCOL) /* too big. */
ncol = NCOL;
}
/*
* typeahead returns TRUE if there are characters available to be read
* in.
*/
typeahead() {
int x;
return((ioctl(0, FIONREAD, (char *) &x) < 0) ? 0 : x);
}
/*
* panic - just exit, as quickly as we can.
*/
panic(s) char *s; {
printf(stderr, "panic: %s\n", s);
abort(); /* To leave a core image. */
}
SHAR_EOF
fi # end of overwriting check
if test -f 'sys/vms/aaareadme.1st'
then
echo shar: will not over-write existing file "'sys/vms/aaareadme.1st'"
else
cat << \SHAR_EOF > 'sys/vms/aaareadme.1st'
This directory ([.SYS.VMS]) contains the VMS-specific files for MicroGnuEmacs.
+-----------------------+
| Construction |
+-----------------------+
By this point you should have put the ``system-independent'' files into
a directory of your choice, then put the VMS files into the subdirectory
[.SYS.VMS]. You should also put the termcap terminal driver into the
subdirectory [.TTY.TERMCAP].
The command file MAKE.COM is designed to compile and link the entire
program, using the VMS system functions and the termcap terminal driver.
To invoke MAKE.COM, enter
SET DEF dev:[emacs-dir] ! location of system-independent files
@[.SYS.VMS]MAKE ! go have some coffee...
This will create the termcap library, compile each of the necessary
modules, and link the entire program into dev:[emacs-dir]MG.EXE.
NOTE: To keep the size of the executable program down,
[.SYS.VMS]MGLINK.COM attempts to link in the VAX C shareable run-time
library. If the command procedure finds the file SYS$SHARE:VAXCRTL.EXE,
it attempts to link to it, else it defaults to SYS$LIBRARY:VAXCRTL.OLB
for the runtime library.
+-------------------------------------------------------+
| Specifying Your Terminal With Termcap |
+-------------------------------------------------------+
(CAVEAT AND CREDITS: The termcap library in [.SYS.VMS.TERMCAP] was
written by Fred Fish (of Amiga Public Domain Library fame) and placed in
the public domain. It is not guaranteed to be a complete implementation
of the Unix termcap(5) library; the usual disclaimers (like "it works
for me":-) apply here. I have modified it to support the tc=
capability, which lets you define terminals in terms (pardon the pun) of
other terminals, so it should work reasonably well with the termcap
provided in [.SYS.VMS.TERMCAP]TERMCAP.)
To use the termcap library, you need to tell it where to find a terminal
definition (termcap) file. On Unix systems, this is found in a file
called /etc/termcap. To emulate the same behavior on VMS, DEFINE/JOB the
logical name ETC to point to a directory that contains a termcap file,
with the name TERMCAP. (no extension). (The /JOB qualifier is needed
when you run MicroGnuEmacs as a spawned supprocess.)
If your system has Eunice, there is a large termcap file already
available via this exact mechanism, so you shouldn't need to define ETC
at all. If you don't have Eunice, never fear; a termcap resides in the
file [.SYS.VMS.TERMCAP]TERMCAP., so all you have to do is
DEFINE ETC [emacs-directory.SYS.VMS.TERMCAP]
to get started. You get the idea. Lastly, if your site uses the logical
name ETC for another purpose, you can define the logical name TERMCAP
to point to the MG termcap file. You must specify the path in Unix format,
with the root being the disk drive the file resides on. For example,
if the termcap file is in DUA0:[USER]TERMCAP., the command would be
DEFINE TERMCAP "/dua0/user/termcap"
The VAX C run-time library can translate this into the appropriate
VMS file specification for you (a rather nice feature...).
Once you've indicated where the termcap file is,
DEFINE/JOB TERM "termtype"
where "termtype" is in lower case and matches an entry in the termcap
file. This tells MicroEmacs (even when it runs in another process) what
your terminal type is.
NOTE: One performance aspect of termcap files is that they are searched
sequentially, so you may want to move the most frequently used terminals
at your site to the beginning of the file to minimize startup overhead.
+---------------------------------------+
| INVOKING MG |
+---------------------------------------+
First of all, remember to set up the logical names for the terminal
type and termcap file:
$ DEFINE/JOB ETC dev:[dir] ! location of TERMCAP. file
(or)$ DEFINE/JOB TERMCAP "/disk/dir1/dir2/termcapfile"
$ DEFINE/JOB TERM "termtype" ! termtype is lower case
(Obviously, this can be done just once, in your LOGIN.COM file.)
Then, to just run MicroGnuEmacs in your current process,
$ RUN [emacs-directory]MG
Or you can define a symbol to run it with command line arguments:
$ MG :== $dev:[emacs-directory]MG
$ MG [file]
+---------------------------------------+
| MG As a Kept Fork |
+---------------------------------------+
You can use [.SYS.VMS]MG.COM to spawn a MicroEmacs subjob, which you
can then attach to and pop out of as you please. Edit the line at the
top of MG.COM that defines the path to the image MG.EXE, then define a
global symbol called MG:
$ MG :== @dev:[emacs-directory.SYS.VMS]MG
You can then use MG to edit files:
$ MG [file]
When inside MicroGnuEmacs, use the command M-x suspend-emacs (bound to
C-z by default) to suspend the MicroGnuEmacs process and attach your
terminal to the process that spawned it. To re-attach to
MicroGnuEmacs, just issue the MG command again:
$ MG [file]
The command file will reattach you to your MicroGnuEmacs process,
where you can continue editing where you left off. If you specify a
new file to edit, the command file sets a logical name which
MicroGnuEmacs then looks at when you reattach.
Note that this functionality may not be identical to what happens in
real GNU Emacs for VMS. However, it does provide a facility that you
don't really want to do without.
+---------------------------------------+
| MicroGnuEmacs As a Mail Editor |
+---------------------------------------+
As an added bonus, the file MGMAILEDIT.COM makes MicroGnuEmacs your
mail editor when you use the SEND/EDIT command. Just issue the
command
DEFINE/JOB MAIL$EDIT dev:[dir]MGMAILEDIT.COM
to inform the mail system you want to use MGMAILEDIT.COM, then whenever
you issue SEND/EDIT inside mail, MG will be used as your mail editor.
SHAR_EOF
fi # end of overwriting check
if test -f 'sys/vms/bcopy.mar'
then
echo shar: will not over-write existing file "'sys/vms/bcopy.mar'"
else
cat << \SHAR_EOF > 'sys/vms/bcopy.mar'
.title bcopy MicroEmacs access to movc3
;
; Mic Kaczmarczik
; July 11, 1986
;
; This code implements the bcopy() function for quick
; memory copies in VAX C.
;
.entry bcopy,^m<r2,r3,r4,r5> ; MOVC3 side-effects r0-r5
subl2 #4,sp ; Step over call frame
movc3 12(ap), at 4(ap), at 8(ap) ; Copy them bytes
ret ; Bye!
.end
SHAR_EOF
fi # end of overwriting check
if test -f 'sys/vms/ccom.com'
then
echo shar: will not over-write existing file "'sys/vms/ccom.com'"
else
cat << \SHAR_EOF > 'sys/vms/ccom.com'
$ Verify = F$Verify(0)
$!
$! CCOM.COM
$!
$! Run the C compiler on P1, but only if the .c file
$! is newer than the corresponding .obj file.
$!
$! Usage:
$! @CCOM [file [qualifiers]]
$!
$ If P1 .Eqs. "" Then -
Inquire P1 "C Source File"
$ Name = P1 - ".C"
$ Source = Name + ".C"
$ Object = Name + ".OBJ"
$!
$! See if both files exist. If both exist, only compile the
$! source if the revision date is greater than or equal to
$! that of the object file.
$!
$ If F$Search(Source) .Eqs. "" Then -
Goto NoSource
$ If F$Search(Object) .Eqs. "" Then -
$ Goto Compile
$ SDate = F$File_Attributes(Source, "RDT")
$ ODate = F$File_Attributes(Object, "RDT")
$ If SDate .Lts. ODate Then -
Goto Bye
$!
$! Compile the program
$!
$Compile:
$ On Error Then Goto Fail
$ Write Sys$Output "Compiling " + Source
$ CC 'P2' 'Source
$ If F$Search(Object) .Eqs. "" Then -
Goto Fail
$!
$! Done.
$!
$Bye:
$ If Verify Then -
Set Verify
$ Exit
$!
$NoSource:
$ Write Sys$Output "%CCOM-F-NOTFOUND, file not found"
$ Goto Bye
$!
$Fail:
$ Write Sys$Output "%CCOM-F-FAIL, compile failed"
$ Goto Bye
SHAR_EOF
fi # end of overwriting check
if test -f 'sys/vms/make.com'
then
echo shar: will not over-write existing file "'sys/vms/make.com'"
else
cat << \SHAR_EOF > 'sys/vms/make.com'
$ on error then goto trouble
$ on severe_error then goto trouble
$ default = f$trnlnm("SYS$DISK") + f$directory()
$!
$! Command procedure to build MicroGnuEmacs on VMS systems.
$!
$! Compile-time options you can set by appropriate assignments to
$! "ccomflags" and "linkflags". Defining these flags asks for
$! a particular feature.
$!
$! /DEFINE:"STARTUP" -- look for SYS$LOGIN:.MG startup file
$! /DEFINE:"FLOWCONTROL" -- use ^S, ^Q for flow control
$!
$! Set compilation and linking options. The first commented-out-line is
$! the set I use...
$ ccomflags := "/define:""STARTUP"" "
$! ccomflags := "/define:(""STARTUP"",""XKEYS"",""PREFIXREGION"") "
$! ccomflags := "/debug" ! if you want to debug the program
$!
$ linkflags := ""
$! linkflags := "/debug" ! to debug the program
$!
$! To make MG,
$!
$! Set def to the top level MicroGnuEmacs directory and type
$!
$! @[.SYS.VMS]MAKE
$!
$! to get things rolling.
$!
$!* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
$! Create the termcap library
$!
$ set def [.sys.vms.termcap]
$ @createlib.com
$ set def [---]
$!* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
$! Define a search path for source files. This is important
$! because
$! 1) The search path lets us to keep these files in
$! separate directories
$! 2) When searching for quoted #include files (e.g.
$! #include "def.h"), VAX C uses the default file
$! specification set up by the source file name.
$!
$! If we use mgsrc:foo.c, the search list becomes
$! part of the default file spec, and the compiler
$! can find the system- and terminal-specific
$! header files. This acts as a substitute for the
$! -I flag found on most Unix C compilers.
$!
$! A side effect of the search list is that the object files get
$! created in the top level directory, which I prefer.
$!
$ define mgsrc [],[.sys.vms],[.tty.termcap]
$!
$! Define alias for the compilation command. By default, use a
$! command file that checks revision dates and only compiles when
$! it has to. If you want to force a total recompile, switch the
$! comments around.
$!
$ ccom := @mgsrc:ccom
$! ccom := cc
$!
$! Compile all the basic files
$!
$ ccom mgsrc:basic 'ccomflags
$ ccom mgsrc:buffer 'ccomflags
$ ccom mgsrc:cinfo 'ccomflags
$ ccom mgsrc:display 'ccomflags
$ ccom mgsrc:echo 'ccomflags
$ ccom mgsrc:extend 'ccomflags
$ ccom mgsrc:file 'ccomflags
$ ccom mgsrc:kbd 'ccomflags
$ ccom mgsrc:line 'ccomflags
$ ccom mgsrc:main 'ccomflags
$ ccom mgsrc:match 'ccomflags
$ ccom mgsrc:paragraph 'ccomflags
$ ccom mgsrc:prefix 'ccomflags
$ ccom mgsrc:random 'ccomflags
$ ccom mgsrc:region 'ccomflags
$ ccom mgsrc:search 'ccomflags
$ ccom mgsrc:symbol 'ccomflags
$ ccom mgsrc:version 'ccomflags
$ ccom mgsrc:window 'ccomflags
$ ccom mgsrc:word 'ccomflags
$!
$! Compile the terminal interface
$!
$ ccom mgsrc:tty 'ccomflags
$ ccom mgsrc:ttykbd 'ccomflags
$!
$! Compile the VMS-specific files
$!
$ ccom mgsrc:fileio 'ccomflags
$ ccom mgsrc:spawn 'ccomflags
$ ccom mgsrc:trnlnm 'ccomflags
$ ccom mgsrc:ttyio 'ccomflags/define:"FLOWCONTROL=0"
$ macro mgsrc:bcopy
$!
$! Link the program
$!
$ @[.sys.vms]mglink "''linkflags'"
$!
$! We're done!
$!
$ write sys$output "MicroEmacs build completed."
$ set default 'default
$ exit
$!
$! Trouble somewhere -- go 'way
$!
$trouble:
$ write sys$output "Problem building MicroEmacs!!!!!"
$ set default 'default
$ exit
SHAR_EOF
fi # end of overwriting check
if test -f 'sys/vms/mg.com'
then
echo shar: will not over-write existing file "'sys/vms/mg.com'"
else
cat << \SHAR_EOF > 'sys/vms/mg.com'
$ Verify = 'F$Verify(0)
$!
$! MG.COM
$!
$! Usage:
$! @MG [file1 [file2 [...]]] ! To start up MG
$! @MG [file] ! To reattach to MG after ^Z
$!
$! MG.COM implements a "kept-fork" capability for MG, allowing you to pop
$! in and out of the editor without reloading it all the time. If a
$! process called user_MG (where user is your username) exists, this
$! command file attempts to attach to it. If not, it silently spawns a
$! subjob to run Emacs for you.
$!
$! To `keep' MG around once you get into it, use "suspend-emacs" (bound
$! to C-z by default) to suspend MG and attach back to the process
$! pointed to by MG$AttachTo.
$!
$! To get back into MG from DCL enter @MG again. You may optionally
$! specify *one* new file name, in which case MG will attempt to
$! visit that file when you re-attach.
$!
$!----------------------------------------------------------------
$!
$! Set things up. Change the definition of MG_Name to whatever you like.
$! You'll *have* to redefine MG_PROG, of course...
$!
$ MG_Name = F$Edit(F$Getjpi("","USERNAME"),"TRIM") + "_MG"
$ MG_Prog = "Disk$Staff:[Ccep001.Proj.Mg3]MG.Exe"
$ MG_Base = MG_Name ! Used for additions
$ If F$Length(MG_Base) .GT. 13 Then - ! Truncate base for _1,_2...
$ MG_Base = F$Extract(0,13,MG_Base)
$ Proc = F$GetJpi("","PRCNAM")
$ Master_Pid = F$Getjpi("","MASTER_PID")
$!
$! Define logical names used for communicating with MG
$!
$ Define/Nolog/Job MG$AttachTo "''Proc'"
$ Define/Nolog/Job MG$File " " ! No file by default
$ If P1 .Nes. "" Then -
Define/Nolog/Job MG$File "''P1'"
$!
$! Attempt to find MG subprocess in current tree. If found, attach
$! to it, else spawn a new MG process
$!
$ Save_Priv = F$SetPrv("NOWORLD,NOGROUP") ! Only look in job tree
$ Try_Count = 1
$Search:
$ Context = "" ! Set up process search context
$ProcLoop:
$ Pid = F$Pid(Context) ! Get next PID
$ If Pid .Eqs. "" Then -
Goto Spawn ! No MG_Name found; spawn a process
$ If F$GetJpi(Pid,"PRCNAM") .Nes. MG_Name Then -
Goto Procloop ! Try next process
$! Process name matches; see if it's in our job
$ If F$GetJpi(Pid,"MASTER_PID") .Eqs. Master_Pid Then -
Goto Attach ! Found process in our job!
$! Process name matches, but isn't in our job. Re-start search
$ MG_Name = MG_Base + "_" + F$String(Try_Count)
$ Try_Count = Try_Count + 1
$ Goto Search
$!
$! Here to attach to a process in our tree. Set message to
$! turn off the "Attaching to..." message
$!
$Attach:
$ Message = F$Environment("MESSAGE")
$ Set Proc/Priv=('Save_Priv') ! Restore privileges
$ Set Message/NoFacility/NoIdentification/NoSeverity/NoText
$ Attach "''MG_Name'"
$ Set Message/Facility/Identification/Severity/Text
$ Goto Done
$!
$! Here if can't attach. Spawn a new MG process
$!
$Spawn:
$ Set Process/Priv=('Save_Priv') ! Restore privileges
$ MG$MG :== $'MG_Prog' ! Avoid recursion
$ Spawn/NoLog/Proc="''MG_Name'" MG$MG 'P1' 'P2' 'P3' 'P4' 'P5' 'P6' 'P7' 'P8'
$ Delete/Symbol/Global MG$MG ! Get rid of it
$Done:
$!
$! Here once we reconnect from MG, whether we detached or exited.
$!
$ Deassign/Job MG$File
$ Deassign/Job MG$AttachTo
$ If Verify Then -
Set Verify
SHAR_EOF
fi # end of overwriting check
if test -f 'sys/vms/mglink.com'
then
echo shar: will not over-write existing file "'sys/vms/mglink.com'"
else
cat << \SHAR_EOF > 'sys/vms/mglink.com'
$!
$! Link MicroGnuEmacs object files into MG.EXE
$!
$! Note: This command procedure is designed to be executed
$! in the main microEmacs directory.
$!
$! Further note: If the VAX C shareable run-time library is
$! found in SYS$SHARE, the command procedure uses it.
$! If not found, it uses SYS$LIBRARY:VAXCRTL.
$
$ runtime_library := sys$library:vaxcrtl.olb/lib
$ if f$search("SYS$SHARE:VAXCRTL.EXE") .nes. "" then -
runtime_library := [.sys.vms]emacs.opt/opt
$ link'p1'/exec=sys$disk:[]mg.exe basic.obj, buffer.obj, cinfo.obj, -
display.obj, echo.obj, extend.obj, file.obj, kbd.obj, line.obj, -
main.obj, match.obj, paragraph.obj, prefix.obj, random.obj, -
region.obj, search.obj, symbol.obj, version.obj, window.obj, word.obj, -
tty.obj, ttykbd.obj, -
fileio.obj, spawn.obj, trnlnm.obj, ttyio.obj, bcopy.obj, -
[.sys.vms.termcap]termcap.olb/lib,-
'runtime_library'
SHAR_EOF
fi # end of overwriting check
if test -f 'sys/vms/mgmailedit.com'
then
echo shar: will not over-write existing file "'sys/vms/mgmailedit.com'"
else
cat << \SHAR_EOF > 'sys/vms/mgmailedit.com'
$ Verify = 'F$Verify(0)
$ ! Command procedure to invoke MG from MAIL. You should
$ ! have the symbol MG globally defined, either as
$ !
$ ! MG :== $dev:[dir]MG
$ !
$ ! Then
$ ! DEFINE MAIL$EDIT dev:[dir]MGMAILEDIT.COM
$ !
$ ! to make MAIL look for this file.
$ !
$ ! or, if using the kept-fork capability,
$ !
$ ! MG :== @dev:[dir]MG.COM
$ !
$ ! Inputs:
$ !
$ ! P1 = Input file name.
$ ! P2 = Output file name.
$ !
$ ! The default directory is the same as the parent process.
$ !
$ ! Copy the input file to the output file, then invoke MG on it.
$ !
$ Set Noon
$ Define/Job MG$AttachTo "''F$Process()'"
$ If P2 .Nes. "" .AND. P1 .Nes. "" Then Copy 'P1' 'P2'
$ Define/User Sys$Input Sys$Command
$ MG 'P2'
$ If F$Trnlnm("MG$AttachTo") .Nes. "" Then - ! MG.COM might have done it already
Deassign/Job MG$AttachTo
$ If Verify Then -
Set Verify
SHAR_EOF
fi # end of overwriting check
if test -f 'sys/vms/emacs.opt'
then
echo shar: will not over-write existing file "'sys/vms/emacs.opt'"
else
cat << \SHAR_EOF > 'sys/vms/emacs.opt'
SYS$SHARE:VAXCRTL.EXE/SHARE
SHAR_EOF
fi # end of overwriting check
if test -f 'sys/vms/fileio.c'
then
echo shar: will not over-write existing file "'sys/vms/fileio.c'"
else
cat << \SHAR_EOF > 'sys/vms/fileio.c'
/*
* Name: MicroEMACS
* Version: 30
* VAX/VMS file I/O.
* Last edit: 05-Feb-86
* By: rex::conroy
* decvax!decwrl!dec-rhea!dec-rex!conroy
*
* Read and write ASCII files. All
* of the low level file I/O knowledge is here.
* VAX/VMS.
* Pretty much vanilla standard I/O, using
* the (traditional) funny open.
*/
#include "def.h"
static FILE *ffp;
/*
* Open a file for reading.
*/
ffropen(fn)
char *fn;
{
if ((ffp=fopen(fn, "r")) == NULL)
return (FIOFNF);
return (FIOSUC);
}
/*
* Open a file for writing.
* Return TRUE if all is well, and
* FALSE on error (cannot create).
*/
ffwopen(fn)
char *fn;
{
register int fd;
if ((fd=creat(fn, 0, "rfm=var", "rat=cr")) < 0
|| (ffp=fdopen(fd, "w")) == NULL) {
ewprintf("Cannot open file for writing");
return (FIOERR);
}
return (FIOSUC);
}
/*
* Close a file.
* Should look at the status.
*/
ffclose()
{
fclose(ffp);
return (FIOSUC);
}
/*
* Write a line to the already
* opened file. The "buf" points to the
* buffer, and the "nbuf" is its length, less
* the free newline. Return the status.
* Check only at the newline.
*/
ffputline(buf, nbuf)
register char buf[];
{
register int i;
for (i=0; i<nbuf; ++i)
putc(buf[i]&0xFF, ffp);
putc('\n', ffp);
if (ferror(ffp) != FALSE) {
ewprintf("Write I/O error");
return (FIOERR);
}
return (FIOSUC);
}
/*
* Read a line from a file, and store the bytes
* in the supplied buffer. Stop on end of file or end of
* line. Don't get upset by files that don't have an end of
* line on the last line; this seem to be common on CP/M-86 and
* MS-DOS (the suspected culprit is VAX/VMS kermit, but this
* has not been confirmed. If this is sufficiently researched
* it may be possible to pull this kludge). Delete any CR
* followed by an LF. This is mainly for runoff documents,
* both on VMS and on Ultrix (they get copied over from
* VMS systems with DECnet).
* (17-Jul-1986 MPK) strip NULs too.
*/
ffgetline(buf, nbuf)
register char buf[];
{
register int c;
register int i;
i = 0;
for (;;) {
c = getc(ffp);
if (c == '\r') { /* Delete any non-stray */
c = getc(ffp); /* carriage returns. */
if (c != '\n') {
if (i >= nbuf-1) {
ewprintf("File has long line");
return (FIOERR);
}
buf[i++] = '\r';
}
}
if (c==EOF || c=='\n') /* End of line. */
break;
if (c == '\0') /* strip NULs */
continue;
if (i >= nbuf-1) {
ewprintf("File has long line");
return (FIOERR);
}
buf[i++] = c;
}
if (c == EOF) { /* End of file. */
if (ferror(ffp) != FALSE) {
ewprintf("File read error");
return (FIOERR);
}
if (i == 0) /* Don't get upset if */
return (FIOEOF); /* no newline at EOF. */
}
buf[i] = 0;
return (FIOSUC);
}
/*
* VMS has version numbers, so there is
* no need for MicroEMACS to bother making its own
* flavour of backup copy. Return TRUE so the
* caller doesn't quit.
*/
fbackupfile(fname)
char *fname;
{
return (TRUE);
}
/*
* The string "fn" is a file name.
* Perform any required case adjustments. All sustems
* we deal with so far have case insensitive file systems.
* We zap everything to lower case. The problem we are trying
* to solve is getting 2 buffers holding the same file if
* you visit one of them with the "caps lock" key down.
* On UNIX file names are dual case, so we leave
* everything alone.
*/
adjustcase(fn)
register char *fn;
{
register int c;
while ((c = *fn) != 0) {
if (c>='A' && c<='Z')
*fn = c + 'a' - 'A';
++fn;
}
}
#ifndef MICRO
#include <file.h>
/*
* Find the user's startup file, and return its name.
* Use the VAX C getenv() function, which returns the VMS
* directory spec for the user's home directory.
* Check for ${HOME}.emacs, then for ${HOME}.mg, then give up.
*/
char *
startupfile() {
register char *file;
static char home[NFILEN];
char *getenv();
if ((file = getenv("HOME")) == NULL) return NULL;
if (strlen(file)+7 >= NFILEN - 1) return NULL;
(VOID) strcpy(home, file);
file = &(home[strlen(home)]);
(VOID) strcpy(file, ".mg");
if (access(home, O_RDONLY ) == 0) return home;
(VOID) strcpy(file, ".emacs");
if (access(home, O_RDONLY) == 0) return home;
return NULL;
}
#endif
SHAR_EOF
fi # end of overwriting check
if test -f 'sys/vms/spawn.c'
then
echo shar: will not over-write existing file "'sys/vms/spawn.c'"
else
cat << \SHAR_EOF > 'sys/vms/spawn.c'
/*
* Name: MicroEMACS
* VAX/VMS spawn and attach to a DCL subprocess.
* Created: rex::conroy
* decvax!decwrl!dec-rhea!dec-rex!conroy
* Modified:
* 19-May-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic
* Add att-to-parent command to attach to the parent
* process. If we can't attach to parent somehow,
* spawn a DCL subjob. This gives us the same
* suspend capability as Unix Emacses.
*
* As an added hook, you can DEFINE/JOB
* MG$ATTACHTO to a process name, and
* the code will try to attach to that name.
*
* Also, if the logical name MG$FILE is
* defined, attachtoparent() will visit that file
* when you re-attach to Emacs. This is useful
* for a lot of applications, especially MAIL/EDIT...
* 26-Jun-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic
* Specify process we're attaching to when we attempt
* to attach to it.
* 03-Sep-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic
* Call savebuffers() before leaving the editor.
* Unlike csh, DCL has no problem with people
* logging out without completing subjobs...
* #define NOSAVEONZ if you don't want this behavior.
* 13-Oct-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic
* Change MICROEMACS$... to MG$... for consistency.
*/
#include "def.h"
#include <ssdef.h>
#include <stsdef.h>
#include <descrip.h>
#include <iodef.h>
#include <jpidef.h>
#define EFN 0 /* Event flag. */
extern int oldmode[3]; /* In "ttyio.c". */
extern int newmode[3];
extern short iochan;
extern int ckttysize(); /* Checks for new term size */
#ifndef NOSAVEONZ
extern int savebuffers(); /* Save all buffers before */
#endif
/*
* Create a subjob with a copy
* of the command intrepreter in it. When the
* command interpreter exits, mark the screen as
* garbage so that you do a full repaint. Bound
* to "C-C" and called from "C-Z". The message at
* the start in VMS puts out a newline. Under
* some (unknown) condition, you don't get one
* free when DCL starts up.
*/
spawncli(f, n, k)
{
register int s;
#ifndef NOSAVEONZ
if (savebuffers() == ABORT) /* TRUE means all saved,*/
return (ABORT); /* FALSE means not. */
#endif
eerase(); /* Get rid of echo line */
ttcolor(CTEXT); /* Normal color. */
ttnowindow(); /* Full screen scroll. */
ttmove(nrow-1, 0); /* Last line. */
eputs("Starting DCL");
ttputc('\r');
ttputc('\n');
ttflush();
sgarbf = TRUE;
s = sys(NULL); /* NULL => DCL. */
return (s);
}
/*
* Run a command. The "cmd" is a pointer
* to a command string, or NULL if you want to run
* a copy of DCL in the subjob (this is how the standard
* routine LIB$SPAWN works. You have to do wierd stuff
* with the terminal on the way in and the way out,
* because DCL does not want the channel to be
* in raw mode.
*/
sys(cmd)
register char *cmd;
{
struct dsc$descriptor cdsc;
struct dsc$descriptor *cdscp;
long status;
long substatus;
long iosb[2];
status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
oldmode, sizeof(oldmode), 0, 0, 0, 0);
if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
return (FALSE);
cdscp = NULL; /* Assume DCL. */
if (cmd != NULL) { /* Build descriptor. */
cdsc.dsc$a_pointer = cmd;
cdsc.dsc$w_length = strlen(cmd);
cdsc.dsc$b_dtype = DSC$K_DTYPE_T;
cdsc.dsc$b_class = DSC$K_CLASS_S;
cdscp = &cdsc;
}
status = LIB$SPAWN(cdscp, 0, 0, 0, 0, 0, &substatus, 0, 0, 0);
if (status != SS$_NORMAL)
substatus = status;
ckttysize(); /* check for new terminal size */
status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
newmode, sizeof(newmode), 0, 0, 0, 0);
if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
return (FALSE);
if ((substatus&STS$M_SUCCESS) == 0) /* Command failed. */
return (FALSE);
return (TRUE);
}
/*
* Front end for combined attach-to-parent and spawn-cli action
*/
attachtoparent(f, n, k)
{
register int s;
s = attparent();
if (s == ABORT)
return (ABORT);
else if (s == FALSE)
return spawncli(f, n, k); /* better than nothing */
else
return (TRUE);
}
/*
* Attach to parent. If the logical name MG$ATTACHTO
* is present, attempt to attach to it. If not, attempt to
* attach to parent process.
*
* On return, see if the logical name MG$FILE contains
* anything, and try to visit that file.
*/
static $DESCRIPTOR(nmdsc,"MG$ATTACHTO");
attparent()
{
long pid, jpi_code;
char equiv[18], msgbuf[60];
struct dsc$descriptor_s eqdsc;
short eqlen;
int status, pos;
register BUFFER *bp;
BUFFER *findbuffer();
int s;
/* Set up string descriptor */
eqdsc.dsc$a_pointer = equiv;
eqdsc.dsc$w_length = sizeof(equiv);
eqdsc.dsc$b_dtype = DSC$K_DTYPE_T;
eqdsc.dsc$b_class = DSC$K_CLASS_S;
/* Try to translate MG$ATTACH */
status = lib$sys_trnlog(&nmdsc, &eqdsc.dsc$w_length, &eqdsc);
if (status!=SS$_NORMAL && status!=SS$_NOTRAN) {
ewprintf("Error translating %s",nmdsc.dsc$a_pointer);/* DEBUG */
return (FALSE);
}
if (status == SS$_NORMAL) {
/* Found a translation -- attempt to attach to it */
jpi_code = JPI$_PID;
status = lib$getjpi(&jpi_code,0,&eqdsc,&pid,0);
equiv[eqdsc.dsc$w_length] = '\0';
if (status != SS$_NORMAL) {
ewprintf("Error getting JPI for \"%s\"",equiv);
return (FALSE);
}
#ifndef NOSAVEONZ
/* Attempt to attach to named process. Save all buffers, */
/* set sgarbf because attach() always trashes the display */
if (savebuffers() == ABORT)
return (ABORT);
#endif
/* indicate process we're attaching to */
strcpy(msgbuf,"Attaching to process \"");
for (pos = strlen(equiv) - 1; pos >= 0; --pos)
if (equiv[pos] != ' ') {
equiv[pos+1] = '\0';
break;
}
strcat(msgbuf,equiv);
strcat(msgbuf,"\"");
sgarbf = TRUE;
if (attach(pid,msgbuf) == FALSE) /* whups -- try spawn */
return (FALSE);
}
else { /* No translation -- attempt to find parent process */
jpi_code = JPI$_OWNER;
status = lib$getjpi(&jpi_code,0,0,&pid,0,0);
if ((status != SS$_NORMAL) || (pid == 0)) /* not found! */
return (FALSE);
#ifndef NOSAVEONZ
if (savebuffers() == ABORT)
return (ABORT);
#endif
sgarbf = TRUE;
if (attach(pid,"Attaching to parent process") == FALSE)
return (FALSE);
}
newfile(); /* attempt to find a new file, but don't care */
/* if we don't find one... */
refresh(FALSE, 0, KRANDOM);
return (TRUE);
}
/*
* If we find after re-attaching that there is
* a new file to be edited, attempt to read it in,
* using essentially the same code as findfile().
*/
static newfile()
{
register BUFFER *bp;
register int s;
char filename[NFILEN];
BUFFER *findbuffer();
if ((s = cknewfile(filename, sizeof filename)) != TRUE)
return (s);
if ((bp = findbuffer(filename, &s)) == NULL)
return (s);
curbp = bp;
if (showbuffer(bp, curwp, WFHARD) != TRUE)
return (FALSE);
if (bp->b_fname[0] == 0)
return (readin(filename)); /* Read it in. */
return (TRUE);
}
/*
* Attach to a process by process number. Restore the
* terminal channel to the way it was when we started.
* Also put out an optional message to the user.
*/
static attach(pid, msg)
long pid;
char *msg;
{
long status, attstatus;
long iosb[2];
ttcolor(CTEXT); /* Normal color. */
ttnowindow(); /* Full screen scroll. */
ttmove(nrow-1, 0); /* Last line. */
if (msg) { /* Display a message */
eputs(msg);
ttputc('\r');
ttputc('\n');
}
ttflush();
/* Set terminal to old modes */
status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
oldmode, sizeof(oldmode), 0, 0, 0, 0);
if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
return (FALSE);
/* Attach to the process */
attstatus = LIB$ATTACH(&pid);
/* Return terminal to the modes MG needs */
ckttysize(); /* check for new terminal size first */
status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
newmode, sizeof(newmode), 0, 0, 0, 0);
if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
return (FALSE);
return (attstatus == SS$_NORMAL ? TRUE : FALSE);
}
/*
* Attempt to translate MG$FILE into fname.
* If it's there and non-empty, return TRUE.
*/
static $DESCRIPTOR(filedsc,"MG$FILE");
static cknewfile(fname,fnsiz)
char *fname;
int fnsiz;
{
char equiv[NFILEN];
struct dsc$descriptor_s eqdsc;
short len;
register int status;
eqdsc.dsc$a_pointer = equiv;
eqdsc.dsc$w_length = sizeof(equiv);
eqdsc.dsc$b_dtype = DSC$K_DTYPE_T;
eqdsc.dsc$b_class = DSC$K_CLASS_S;
status = lib$sys_trnlog(&filedsc, &len, &eqdsc);
if (status!=SS$_NORMAL && status!=SS$_NOTRAN) {
ewprintf("Error translating MG$FILE");
return (FALSE);
}
if (status == SS$_NOTRAN) /* No new file found */
return (FALSE);
if (equiv[0] == ' ')
return (FALSE);
equiv[len] = '\0';
strcpy(fname, equiv);
return (TRUE);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'sys/vms/trnlnm.c'
then
echo shar: will not over-write existing file "'sys/vms/trnlnm.c'"
else
cat << \SHAR_EOF > 'sys/vms/trnlnm.c'
/*
* Name: MicroEmacs
* VAX/VMS translate logical name routine
* Version: Gnu30
* Last Edit: 10-Jul-86
* By: ...!ihnp4!seismo!ut-sally!ut-ngp!mic
*
*/
/*
*
* Trnlnm()
*
* Description:
* Attempt to translate the logical name logname into an equivalence
* string, using the standard VMS routine LIB$SYS_TRNLOG().
* If a translation exists, return a pointer to the static area
* that contains the null-terminated translation string. If not,
* return 0.
*
* Bugs:
* Returns a pointer to static data that is modified each time
* the routine successfully translates a logical name.
*/
#include <ssdef.h>
#include <descrip.h>
#include <stdio.h>
static char _equiv_buf[256];
static struct dsc$descriptor_s
_equiv = {
sizeof(_equiv_buf), DSC$K_DTYPE_T, DSC$K_CLASS_S, _equiv_buf
},
_name = {
0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL
};
char *trnlnm(logname)
char *logname;
{
short eqlen;
int status;
if (logname == NULL)
return (NULL);
_name.dsc$a_pointer = logname;
_name.dsc$w_length = strlen(logname);
status = lib$sys_trnlog(&_name, &eqlen, &_equiv);
if (status != SS$_NORMAL)
return (NULL);
_equiv_buf[eqlen] = '\0';
return (_equiv_buf);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'sys/vms/ttyio.c'
then
echo shar: will not over-write existing file "'sys/vms/ttyio.c'"
else
cat << \SHAR_EOF > 'sys/vms/ttyio.c'
/*
* Name: MicroGnuEmacs
* VAX/VMS terminal I/O.
* o 16-Apr-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic
* Turn off TTSYNC so ^S and ^Q are sent to program.
* To get this back, compile with -DFLOWCONTROL
* o 10-Jul-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic
* Add setttysize(), typeahead() and panic() for Gnu v30
*/
#include "def.h"
#include <stsdef.h>
#include <ssdef.h>
#include <descrip.h>
#include <iodef.h>
#include <ttdef.h>
#include <tt2def.h>
#define NIBUF 128 /* Probably excessive. */
#define NOBUF 512 /* Not too big for 750/730. */
#define EFN 0 /* Event flag */
char obuf[NOBUF]; /* Output buffer */
int nobuf; /* # of bytes in above */
char ibuf[NIBUF]; /* Input buffer */
int nibuf; /* # of bytes in above */
int ibufi; /* Read index */
int oldmode[3]; /* Old TTY mode bits */
int newmode[3]; /* New TTY mode bits */
short iochan; /* TTY I/O channel */
int nrow; /* Terminal size, rows. */
int ncol; /* Terminal size, columns. */
short ospeed; /* Terminal output speed */
/* for termcap library */
/*
* This routines gets called once, to set up the
* terminal channel.
* On VMS we find the translation of the SYS$COMMAND:
* logical name, assign a channel to it, and set it raw.
*/
ttopen()
{
struct dsc$descriptor idsc;
struct dsc$descriptor odsc;
char oname[40];
int iosb[2];
int status;
odsc.dsc$a_pointer = "SYS$COMMAND";
odsc.dsc$w_length = strlen(odsc.dsc$a_pointer);
odsc.dsc$b_dtype = DSC$K_DTYPE_T;
odsc.dsc$b_class = DSC$K_CLASS_S;
idsc.dsc$b_dtype = DSC$K_DTYPE_T;
idsc.dsc$b_class = DSC$K_CLASS_S;
do {
idsc.dsc$a_pointer = odsc.dsc$a_pointer;
idsc.dsc$w_length = odsc.dsc$w_length;
odsc.dsc$a_pointer = &oname[0];
odsc.dsc$w_length = sizeof(oname);
status = LIB$SYS_TRNLOG(&idsc, &odsc.dsc$w_length, &odsc);
if (status!=SS$_NORMAL && status!=SS$_NOTRAN)
exit(status);
if (oname[0] == 0x1B) {
odsc.dsc$a_pointer += 4;
odsc.dsc$w_length -= 4;
}
} while (status == SS$_NORMAL);
status = SYS$ASSIGN(&odsc, &iochan, 0, 0);
if (status != SS$_NORMAL)
exit(status);
status = SYS$QIOW(EFN, iochan, IO$_SENSEMODE, iosb, 0, 0,
oldmode, sizeof(oldmode), 0, 0, 0, 0);
if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
exit(status);
nrow = (oldmode[1]>>24) & 0xFF; /* Terminal length. */
if (nrow > NROW)
nrow = NROW;
ncol = (oldmode[0]>>16) & 0xFFFF; /* Width. */
if (ncol > NCOL)
ncol = NCOL;
ospeed = (iosb[0]>>24) & 0xFF; /* Speed (for termcap) */
newmode[0] = oldmode[0]; /* Only in version 4. */
#ifdef FLOWCONTROL
newmode[1] = oldmode[1] | TT$M_NOECHO | TT$M_TTSYNC;
#else
newmode[1] = (oldmode[1] | TT$M_NOECHO) & ~TT$M_TTSYNC;
#endif
newmode[2] = oldmode[2] | TT2$M_PASTHRU;
status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
newmode, sizeof(newmode), 0, 0, 0, 0);
if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
exit(status);
}
/*
* This function gets called just
* before we go back home to the command interpreter.
* On VMS it puts the terminal back in a reasonable state.
*/
ttclose()
{
int status;
int iosb[2];
ttflush();
status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
oldmode, sizeof(oldmode), 0, 0, 0, 0);
if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
exit(status);
status = SYS$DASSGN(iochan);
if (status != SS$_NORMAL)
exit(status);
}
/*
* Write a character to the display.
* On VMS, terminal output is buffered, and
* we just put the characters in the big array,
* after checking for overflow.
*/
ttputc(c)
{
if (nobuf >= NOBUF)
ttflush();
obuf[nobuf++] = c;
}
/*
* This function does the real work of
* flushing out buffered I/O on VMS. All
* we do is blast out the block with a write call. No status
* checking is done on the write, because there isn't anything
* clever that can be done, and because you will see the
* error as a messed up screen.
*/
ttflush()
{
int iosb[2];
if (nobuf != 0) {
SYS$QIOW(EFN, iochan, IO$_WRITELBLK|IO$M_NOFORMAT,
iosb, 0, 0, obuf, nobuf, 0, 0, 0, 0);
nobuf = 0;
}
}
/*
* Read a character from the terminal,
* performing no editing and doing no echo at all.
* More complex in VMS that almost anyplace else,
* which figures.
*/
ttgetc()
{
int status;
int iosb[2];
int term[2];
term[0] = 0;
term[1] = 0;
while (ibufi >= nibuf) {
ibufi = 0;
status = SYS$QIOW(EFN, iochan, IO$_READLBLK|IO$M_TIMED,
iosb, 0, 0, ibuf, NIBUF, 0, term, 0, 0);
if (status != SS$_NORMAL)
continue;
status = iosb[0] & 0xFFFF;
if (status!=SS$_NORMAL && status!=SS$_TIMEOUT)
continue;
nibuf = (iosb[0]>>16) + (iosb[1]>>16);
if (nibuf == 0) {
status = SYS$QIOW(EFN, iochan, IO$_READLBLK,
iosb, 0, 0, ibuf, 1, 0, term, 0, 0);
if (status != SS$_NORMAL)
continue;
if ((iosb[0]&0xFFFF) != SS$_NORMAL)
continue;
nibuf = (iosb[0]>>16) + (iosb[1]>>16);
}
}
return (ibuf[ibufi++] & 0xFF);
}
/*
* Internal check for new terminal size.
* Do this *before* setting terminal modes, so
* the size changes are kept when.
*/
ckttysize()
{
int status, mode[3], iosb[2], wid, len;
status = SYS$QIOW(EFN, iochan, IO$_SENSEMODE, iosb, 0, 0,
mode, sizeof(mode), 0, 0, 0, 0);
if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
panic("ckttsize: can't sense terminal modes!");
/* save new page length */
len = (mode[1] >> 24) & 0xFF;
oldmode[1] = (oldmode[1] & 0x00FFFFFF) | (len << 24);
newmode[1] = (newmode[1] & 0x00FFFFFF) | (len << 24);
/* save new page width */
wid = (mode[0] >> 16) & 0xFF;
oldmode[0] = (oldmode[0] & 0x0000FFFF) | (wid << 16);
newmode[0] = (newmode[0] & 0x0000FFFF) | (wid << 16);
}
/*
* Tell Emacs how big the terminal is now,
* making sure the page size is in the range
* 1..NROW.
*/
setttysize()
{
nrow = (newmode[1]>>24) & 0xFF; /* Length. */
if (nrow > NROW)
nrow = NROW;
ncol = (newmode[0]>>16) & 0xFFFF; /* Width. */
if (ncol > NCOL)
ncol = NCOL;
}
/*
* Return the number of characters in the
* typeahead buffer.
*/
typeahead()
{
int status, SYS$QIOW(), iosb[2], mode[2];
status = SYS$QIOW(EFN, iochan, IO$_SENSEMODE|IO$M_TYPEAHDCNT,
iosb, 0, 0, mode, sizeof(mode), 0, 0, 0, 0);
if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
exit(status);
return (mode[0] & 0xFFFF); /* # characters in typeahead buf */
}
#ifdef DPROMPT
/*
* Attempt to read for one character. Return TRUE if the
* read times out after 2 seconds, return immediately with
* FALSE if the user enters something.
*/
ttwait()
{
int status;
int iosb[2];
int term[2];
term[0] = 0; /* no termination characters for read */
term[1] = 0;
while (ibufi >= nibuf) { /* anything in the buffer? */
ibufi = 0; /* nope, read 1 char w/timeout */
status = SYS$QIOW(EFN, iochan, IO$_READLBLK|IO$M_TIMED,
iosb, 0, 0, ibuf, 1, 2, term, 0, 0);
if (status != SS$_NORMAL)
continue; /* did read succeed ? */
status = iosb[0] & 0xFFFF; /* yes, get secondary status */
if (status!=SS$_NORMAL && status!=SS$_TIMEOUT)
continue; /* try again if bad */
nibuf = (iosb[0]>>16) + (iosb[1]>>16);/* store # chars read */
if (status == SS$_TIMEOUT)
return (TRUE); /* the read timed out */
}
return (FALSE); /* read did not time out */
}
#endif DPROMPT
/*
* Just exit, as quickly as we can.
*/
panic(s)
char *s;
{
fprintf(stderr,"panic: %s\n", s);
ttclose(); /* set the terminal back to sane state... */
abort();
}
SHAR_EOF
fi # end of overwriting check
if test -f 'sys/vms/sysdef.h'
then
echo shar: will not over-write existing file "'sys/vms/sysdef.h'"
else
cat << \SHAR_EOF > 'sys/vms/sysdef.h'
/*
* Name: MicroEMACS
* VAX/VMS system header file.
* Version: 29
* Last edit: 05-Feb-86
* By: rex::conroy
* decvax!decwrl!dec-rhea!dec-rex!conroy
*/
#include <ssdef.h>
#define PCC 0 /* "[]" works. */
#define KBLOCK 8192 /* Kill grow. */
#define GOOD (SS$_NORMAL) /* Good exit status. */
typedef int RSIZE; /* Type for file/region sizes */
typedef short KEY; /* Type for internal keystrokes */
/*
* Macros used by the buffer name making code.
* Start at the end of the file name, scan to the left
* until BDC1 (or BDC2, if defined) is reached. The buffer
* name starts just to the right of that location, and
* stops at end of string (or at the next BDC3 character,
* if defined). BDC2 and BDC3 are mainly for VMS.
*/
#define BDC1 ':' /* Buffer names. */
#define BDC2 ']'
#define BDC3 ';'
#define DPROMPT /* use delayed prompts */
SHAR_EOF
fi # end of overwriting check
# End of shell archive
exit 0
More information about the Mod.sources
mailing list