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