[net.sources] New version of mtyconnect for Emacs-write

chris@umcp-cs.UUCP (10/27/83)

In the set of mods to Gosling Emacs, I included a file for doing
ttyconnect() on mpx files.  Well, I'm ashamed to admit I never even
tested it, and it didn't work.  I rewrote it.  Included here is the
result.

Now, you ask, what's a ttyconnect?  Well, if you're running Emacs
and someone writes to you, it scribbles all over your nice screen
and makes you redraw the whole thing (painful at 300 baud!).  With
this feature, you can have a window pop up and you can converse
to your heart's content without heavy pausing.

A sample (simple) program using mtyconnect.c$ttyconnect():

main () {
	char *ttyname (), *s;
	int f;

	s = ttyname (0);
	if (s) {
		if ((f = ttyconnect (s)) < 0)
			f = open (s, 1);	/* open real tty */
		write (f, "Hi there.\n", 10);
	}
}

should print "Hi there." on the terminal -- or, inside Emacs, in
a window.  Note that you're getting a new ttyname() too; this one
knows to look for mpx files in /tmp.

The rest of this file (up to the signature anyway) is mtyconnect.c.

/* mtyconnect.c - connect to a tty under the control of 4.1 bsd Emacs */

#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>

/*
 * This is the other side of the unexpected process handling system for
 * use with Gosling Emacs.  This routine should be loaded in with a
 * program that wants to access another terminal while the user of that
 * terminal is running Emacs.
 *
 *	example:	char *ttyptr;
 *			if ((fd = ttyconnnect (ttyptr)) == -1) {
 *			    perror (ttyptr);
 *			    return;
 *			}
 *
 * where ttyptr points to "/dev/ttyXX" (ie what you would normally open
 * to write directly to the terminal).
 *
 * If ttyconnect() doesn't return -1, then it returns a valid fd.  You can
 * use this descriptor for read()s and write()s.  To close the connection,
 * just close() it.  If it does return -1, you probably want to go open
 * the tty directly.  (The "perror" in the example is really not right.)
 */

static al () {}			/* To break out of open */

#define	ALWAIT	8

ttyconnect (tty) char *tty; {
	int fd;
	char mpxf[40];
	struct stat s;
	int oldalarm;
	time_t t1, t2, time ();
	int (*oldfunc) (), (*signal ()) ();

	if (strncmp (tty, "/dev/", 5))
		return -1;

	/*
	 * Tty is "/dev/ttyXX"; we want to open "/tmp/dev_ttyXX".
	 */

	sprintf (mpxf, "/tmp/dev_%s", &tty[5]);
	if (stat (mpxf, &s) == 0 && ((s.st_mode & S_IFMT) == S_IFMPC)) {
		/*
		 * Get old alarm settings, and find out what time it is.
		 * Set alarm for ALWAIT and try to open the mpx file.
		 * If the open succeeds then done, otherwise reset the
		 * alarm to make it go off as close as possible to the
		 * original time (if any), and return -1.
		 */

		oldalarm = alarm (0);
		t1 = time ((time_t *) 0);
		oldfunc = signal (SIGALRM, al);
		alarm (ALWAIT);
		fd = open (mpxf, 2);
		alarm (0);
		signal (SIGALRM, oldfunc);
		t2 = time ((time_t *) 0);
		if (oldalarm) {
			oldalarm -= (t2 - t1);
			if (oldalarm <= 0)
				oldalarm = 1;
			alarm (oldalarm);
		}
		return fd;
	}
	return -1;
}

/*
 * ttyname (f) int f;
 * Return the the name of the tty belonging to file f,
 * or NULL if it is not a tty.
 */

#define	NULL	0

#include <sys/dir.h>

static char dev[] = "/dev/", tmp[] = "/tmp/";

char *
ttyname (f) int f; {
	struct stat fsb, tsb;
	struct direct db;
	static char rbuf[32];
	register int df;

	if (fstat (f, &fsb) < 0)
		return NULL;

	/*
	 * If multiplexed, look in /tmp
	 */

	if ((fsb.st_mode & S_IFMT) == S_IFMPC) {
		if ((df = open (tmp, 0)) < 0)
			return NULL;
		while (read (df, (char *) &db, sizeof db) == sizeof db) {
			if (db.d_ino == 0 || db.d_ino != fsb.st_ino)
				continue;
			sprintf (rbuf, "%s%.*s", tmp,
					sizeof db.d_name, db.d_name);
			if (stat (rbuf, &tsb))
				continue;
			if (tsb.st_dev == fsb.st_dev) {
				close (df);
				/* lie a little */
				sprintf (rbuf, "%s%.*s", dev,
					sizeof db.d_name - 4, &db.d_name[4]);
				return rbuf;
			}
		}
		close (df);
	}

	/*
	 * The isatty test is a little weird, but better do it for
	 * compatibility.
	 */
	if (isatty (f) == 0)
		return NULL;
	if ((fsb.st_mode & S_IFMT) != S_IFCHR)
		return NULL;
	if ((df = open (dev, 0)) < 0)
		return NULL;
	while (read (df, (char *) &db, sizeof db) == sizeof db) {
		if (db.d_ino == 0 || db.d_ino != fsb.st_ino)
			continue;
		sprintf (rbuf, "%s%.*s", dev, sizeof db.d_name, db.d_name);
		if (stat (rbuf, &tsb) < 0)
			continue;
		if (tsb.st_dev == fsb.st_dev) {
			close (df);
			return rbuf;
		}
	}
	close (df);
	return NULL;
}
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci
UUCP:	{seismo,allegra,brl-bmd}!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris.umcp-cs@CSNet-Relay