4.3BSD/usr/contrib/jove/macros.c

Compare this file to the similar file:
Show the results in this format:

/*************************************************************************
 * This program is copyright (C) 1985, 1986 by Jonathan Payne.  It is    *
 * provided to you without charge for use only on a licensed Unix        *
 * system.  You may copy JOVE provided that this notice is included with *
 * the copy.  You may not sell copies of this program or versions        *
 * modified for use on microcomputer systems, unless the copies are      *
 * included with a Unix system distribution and the source is provided.  *
 *************************************************************************/

#include "jove.h"

struct macro	*macros = 0;		/* Macros */
data_obj	*LastCmd;

static
add_mac(new)
struct macro	*new;
{
	register struct macro	*mp,
				*prev = 0;

	for (mp = macros; mp != 0; prev = mp, mp = mp->m_nextm)
		if (mp == new)
			return;

	if (prev)
		prev->m_nextm = new;
	else
		macros = new;
	new->m_nextm = 0;
	new->Type = MACRO;
}

static
del_mac(mac)
struct macro	*mac;
{
	register struct macro	*m;

	for (m = macros; m != 0; m = m->m_nextm)
		if (m->m_nextm == mac) {
			m->m_nextm = mac->m_nextm;
			break;
		}
	free(mac->Name);
	free(mac->m_body);
	free((char *) mac);
}

struct macro	KeyMacro;	/* Macro used for defining */

#define NMACROS	40		/* This is bad, bad, BAD! */

struct macro	*macstack[NMACROS];
static int	stackp = 0;

fix_macros()
{
	register int	i;
	register struct macro	*mp;

	for (i = 0; macstack[i]; i++) {
		mp = macstack[i];
		macstack[i] = 0;
		mp->m_flags = mp->m_offset = 0;
	}
	stackp = -1;
	KeyMacro.m_flags = KeyMacro.m_offset = 0;
}

static
mac_err(err)
char	*err;
{
	KeyMacro.m_flags = 0;
	MacNolen(&KeyMacro);
	complain(err);
}

do_macro(mac)
struct macro	*mac;
{
	if (mac->m_flags & EXECUTE)
		mac_err("[Attempt to execute macro recursively!]");
	if (++stackp >= NMACROS)
		complain("[Too many macros at once!]");
	macstack[stackp] = mac;
	mac->m_offset = 0;
	mac->m_ntimes = exp;
	mac->m_flags |= EXECUTE;
}

static
MacNolen(m)
struct macro	*m;
{
	m->m_len = m->m_offset = 0;
}

static struct macro *
mac_exists(name)
char	*name;
{
	register struct macro	*mp;

	for (mp = macros; mp; mp = mp->m_nextm)
		if (strcmp(mp->Name, name) == 0)
			return mp;
	return 0;
}

mac_init()
{
	add_mac(&KeyMacro);
	MacNolen(&KeyMacro);
	KeyMacro.Name = "keyboard-macro";
	KeyMacro.m_buflen = 16;
	KeyMacro.m_body = emalloc(KeyMacro.m_buflen);
	KeyMacro.m_ntimes = KeyMacro.m_flags = 0;
	fix_macros();
}

mac_putc(c)
int	c;
{
	if (KeyMacro.m_len >= KeyMacro.m_buflen) {
		KeyMacro.m_buflen += 16;
		KeyMacro.m_body = realloc(KeyMacro.m_body, (unsigned) KeyMacro.m_buflen);
		if (KeyMacro.m_body == 0)
			mac_err("[Can't allocate storage for keyboard macro]");
	}
	KeyMacro.m_body[KeyMacro.m_offset++] = c;
	KeyMacro.m_len++;
}

in_macro()
{
	return ((stackp >= 0) && ((macstack[stackp])->m_flags & EXECUTE));
}

mac_getc()
{
	struct macro	*m;

	if (stackp < 0 || ((m = macstack[stackp])->m_flags & EXECUTE) == 0)
		return -1;
	if (m->m_offset == m->m_len) {
		m->m_offset = 0;
		if (--m->m_ntimes == 0) {
			m->m_flags &= ~EXECUTE;
			stackp--;
		}
		return mac_getc();
	}
	return m->m_body[m->m_offset++];
}

NameMac()
{
	char	*name;
	struct macro	*m;

	if (KeyMacro.m_len == 0)
		complain("[No keyboard macro to name!]");
	if (KeyMacro.m_flags & (DEFINE | EXECUTE))
		complain("[Can't name while defining/executing]");
	if ((m = mac_exists(name = ask((char *) 0, ProcFmt))) == 0)
		m = (struct macro *) emalloc(sizeof *m);
	else {
		if (strcmp(name, KeyMacro.Name) == 0)
			complain("[Can't name it that!]");
		free(m->Name);
		free(m->m_body);
	}
	name = copystr(name);
	m->Type = KeyMacro.Type;
	m->m_len = KeyMacro.m_len;
	m->m_buflen = KeyMacro.m_buflen;
	m->m_body = emalloc(m->m_buflen);
	byte_copy(KeyMacro.m_body, m->m_body, m->m_len);
	m->m_ntimes = m->m_offset = 0;	/* At the beginning */
	m->m_flags = SAVE;
	m->Name = name;
	add_mac(m);
}	

RunMacro()
{
	struct macro	*m;

	if (m = (struct macro *) findmac(ProcFmt))
		do_macro(m);
}

static int	mac_fd;

static
mac_io(fcn, ptr, nbytes)
int	(*fcn)();
char	*ptr;
{
	int	nio;

	if ((nio = (*fcn)(mac_fd, ptr, nbytes)) != nbytes)
		complain("[Macro %s error: %d got %d]",
			 (fcn == read) ? "read" : "write",
			 nbytes,
			 nio);
}

WriteMacs()
{
	struct macro	*m;
	int	namelen,
		netl,
		nmacs = 0;
	char	*file,
		filebuf[FILESIZE];

	file = ask_file((char *) 0, filebuf);
	if ((mac_fd = creat(file, 0666)) == -1)
		complain(IOerr("create", file));
	f_mess("\"%s\"", file);

	/* Don't write the keyboard macro which is always the first */
	for (m = macros->m_nextm; m != 0; m = m->m_nextm) {
		if (m->m_len == 0)
			continue;
		nmacs++;
		netl = htonl(m->m_len);
		mac_io(write, (char *) &netl, sizeof m->m_len);
		namelen = strlen(m->Name) + 1;	/* Including the null */
		netl = htonl(namelen);
		mac_io(write, (char *) &netl, sizeof namelen);
		mac_io(write, m->Name, namelen);
		mac_io(write, m->m_body, m->m_len);
		m->m_flags &= ~SAVE;
	}
	(void) close(mac_fd);
	add_mess(" %d macro%n saved.", nmacs, nmacs);
}

#define NEWWAY	1
#define OLDWAY	0

static int	int_how = NEWWAY;

/* Formatting int's the old way or the new "improved" way? */

#ifndef BSD4_2

/* 4.2 (at least) has these functions defined. */

#if vax || pdp11
long htonl(x)
register long x;
{
	return(	(((x >>  0) & 0377) << 24) |
		(((x >>  8) & 0377) << 16) |
		(((x >> 16) & 0377) <<  8) |
		(((x >> 24) & 0377) <<  0) );
}

short htons(x)
register short x;
{
	return(	(((x >>  0) & 0377) << 8) |
		(((x >>  8) & 0377) << 0) );
}

long ntohl(x)
register long x;
{
	return(	(((x >>  0) & 0377) << 24) |
		(((x >>  8) & 0377) << 16) |
		(((x >> 16) & 0377) <<  8) |
		(((x >> 24) & 0377) <<  0) );
}

short ntohs(x)
register short x;
{
	return(	(((x >>  0) & 0377) << 8) |
		(((x >>  8) & 0377) << 0) );
}
#else
long htonl(x)
register long x;
{
	return(x);
}

short htons(x)
register short x;
{
	return(x);
}

long ntohl(x)
register long x;
{
	return(x);
}

short ntohs(x)
register short x;
{
	return(x);
}
#endif
#endif BSD4_2

int_fmt(i)
{
	if (int_how == NEWWAY)
		return ntohl(i);
	return i;
}

ReadMacs()
{
	char	*file,
		filebuf[FILESIZE];
	struct macro	*m;
	int	nmacs = 0,
		namelen,
		bodylen,
		tmp,
		he_is_sure = 0,
		save_em = FALSE;

	file = ask_file((char *) 0, filebuf);
	if ((mac_fd = open(file, 0)) == -1)
		complain(IOerr("open", file));

	f_mess("\"%s\"", file);
	while (read(mac_fd, (char *) &tmp, sizeof tmp) == (sizeof tmp)) {
retry:		bodylen = int_fmt(tmp);
		if (!he_is_sure && (bodylen <= 0 || bodylen > 10000)) {
			if (int_how == NEWWAY) {
				int_how = OLDWAY;
				save_em = TRUE;
				goto retry;
			} else {
				confirm("Are you sure \"%s\" is a JOVE macro file? ", filebuf);
				he_is_sure = 1;
			}
		}
		nmacs++;
		m = (struct macro *) emalloc (sizeof *m);
		m->m_flags = 0;
		m->m_len = bodylen;
		m->m_buflen = m->m_len;
		mac_io(read, (char *) &namelen, sizeof namelen);
		namelen = int_fmt(namelen);
		m->Name = emalloc(namelen);
		mac_io(read, m->Name, namelen);
		m->m_body = emalloc(m->m_buflen);
		mac_io(read, m->m_body, m->m_len);
		add_mac(m);
	}
	(void) close(mac_fd);
	add_mess(" %d macro%n defined.", nmacs, nmacs);
	if (save_em) {
		char	*msg = "OK to convert to the new format? ",
			ibuf[FILESIZE + 1];

		if (!InJoverc) {
			TOstart("Warning", TRUE);
			Typeout("Warning: your macros file is in the old format.");
			Typeout("Do you want me to convert \"%s\" to the new", pr_name(file));
			Typeout("format?");
			f_mess(msg);
			TOstop();
			confirm(msg);
		}
		/* WriteMacs requests a file name.  This is what it'll get. */
		sprintf(ibuf, "%s\n", file);
		Inputp = ibuf;
		WriteMacs();
	}		
}

Remember()
{
	if (KeyMacro.m_flags & EXECUTE)
		/* We're already executing the macro; ignore any attempts
		   to define the keyboard macro while we are executing. */
		return;
	if (KeyMacro.m_flags & DEFINE)
		message("[Already remembering ... continue with definition]");
	else {
		UpdModLine++;
		KeyMacro.m_flags |= DEFINE;
		MacNolen(&KeyMacro);
		message("Remembering...");
	}
}

/* Is `c' a prefix character */

static
PrefChar(c)
{
	return (int) IsPrefix(mainmap[c]);
}

Forget()
{
	char	*cp;
	struct macro	*m = &KeyMacro;

	UpdModLine++;
	if (m->m_flags & DEFINE) {
		message("Keyboard macro defined.");
		m->m_flags &= ~DEFINE;
		cp = &m->m_body[m->m_len - 2];
		if (PrefChar(*cp))
			m->m_len -= 2;
		else if (commands[*++cp].c_proc == Forget)
			m->m_len--;
	}
}

ExecMacro()
{
	do_macro(&KeyMacro);
}

MacInter()
{
	extern int	Interactive;

	if (!Asking)
		return;
	Interactive = 1;
}

ModMacs()
{
	register struct macro	*m;

	for (m = macros->m_nextm; m != 0; m = m->m_nextm)
		if (m->m_flags & SAVE)
			return 1;
	return 0;
}

data_obj *
findmac(prompt)
char	*prompt;
{
	char	*strings[100];
	register char	**strs = strings;
	register int	com;
	register struct macro	*m = macros;

	for (; m != 0; m = m->m_nextm)
		*strs++ = m->Name;
	*strs = 0;

	if ((com = complete(strings, prompt, NOTHING)) < 0)
		return 0;
	m = macros;
	while (--com >= 0)
		m = m->m_nextm;
	return (data_obj *) m;
}

DelMacro()
{
	struct macro	*m;

	if ((m = (struct macro *) findmac(ProcFmt)) == 0)
		return;
	if (m == &KeyMacro)
		complain("[It's illegal to delete the keyboard-macro!]");
	del_mac(m);
}