btmux/autom4te.cache/
btmux/doc/.svn/
btmux/event/.svn/
btmux/game/.svn/
btmux/game/bin/.svn/
btmux/game/data/.svn/
btmux/game/logs/.svn/
btmux/game/maps/
btmux/game/maps/.svn/
btmux/game/maps/.svn/prop-base/
btmux/game/maps/.svn/props/
btmux/game/maps/.svn/text-base/
btmux/game/maps/.svn/wcprops/
btmux/game/mechs/
btmux/game/mechs/.svn/
btmux/game/mechs/.svn/prop-base/
btmux/game/mechs/.svn/props/
btmux/game/mechs/.svn/text-base/
btmux/game/mechs/.svn/wcprops/
btmux/game/text/.svn/
btmux/include/.svn/
btmux/misc/
btmux/misc/.svn/
btmux/misc/.svn/prop-base/
btmux/misc/.svn/props/
btmux/misc/.svn/text-base/
btmux/misc/.svn/wcprops/
btmux/python/
btmux/python/.svn/
btmux/python/.svn/prop-base/
btmux/python/.svn/props/
btmux/python/.svn/text-base/
btmux/python/.svn/wcprops/
btmux/src/.svn/prop-base/
btmux/src/.svn/props/
btmux/src/.svn/text-base/
btmux/src/.svn/wcprops/
btmux/src/hcode/.svn/
btmux/src/hcode/btech/
btmux/src/hcode/btech/.svn/
btmux/src/hcode/btech/.svn/prop-base/
btmux/src/hcode/btech/.svn/props/
btmux/src/hcode/btech/.svn/text-base/
btmux/src/hcode/btech/.svn/wcprops/
btmux/src/hcode/include/.svn/
/*
 * macro.c - ported from BattleTech 3056 MUSE 
 */

/*
 * $Id: macro.c,v 1.3 2005/08/08 09:43:07 murrayma Exp $ 
 */

#include "copyright.h"
#include "config.h"
#include "macro.h"
#include "commac.h"

#include "config.h"
#include "flags.h"
#include "powers.h"
#include "db.h"
#include "alloc.h"

extern dbref match_thing(dbref player, char *name);


MACENT macro_table[] = {
    {(char *) "add", do_add_macro},
    {(char *) "clear", do_clear_macro},
    {(char *) "chmod", do_chmod_macro},
    {(char *) "chown", do_chown_macro},
    {(char *) "create", do_create_macro},
    {(char *) "def", do_def_macro},
    {(char *) "del", do_del_macro},
    {(char *) "name", do_desc_macro},
    {(char *) "chslot", do_edit_macro},
    {(char *) "ex", do_ex_macro},
    {(char *) "gex", do_gex_macro},
    {(char *) "glist", do_list_macro},
    {(char *) "list", do_status_macro},
    {(char *) "undef", do_undef_macro},
    {(char *) NULL, NULL}
};

void init_mactab(void)
{
    MACENT *mp;

    hashinit(&mudstate.macro_htab, 5 * HASH_FACTOR);

    for (mp = macro_table; mp->cmdname; mp++)
	hashadd(mp->cmdname, (int *) mp, &mudstate.macro_htab);
}

int do_macro(player, in, out)
dbref player;
char *in, **out;
{
    char *s;
    char *cmd;
    MACENT *mp;
    char *old;

    cmd = in + 1;

    if (!isPlayer(player)) {
	notify(player, "MACRO: Only players may use macros.");
	return 0;
    }
    old = alloc_lbuf("do_macro");

    StringCopy(old, in);

    for (s = cmd; *s && *s != ' '; s++);
    if (*s == ' ')
	*s++ = 0;

    mp = (MACENT *) hashfind(cmd, &mudstate.macro_htab);
    if (mp != NULL) {
	(*(mp->handler)) (player, s);
	free_lbuf(old);
	return 0;
    }
    if ((*out = do_process_macro(player, in, s)) != NULL) {
	free_lbuf(old);
	return 1;
    } else {
	StringCopy(in, old);
	free_lbuf(old);
	return 2;		/*
				 * return any value > 1, and command * * *
				 * processing will 
				 */
    }				/*
				 * continue 
				 */
}

void do_list_macro(player, s)
dbref player;
char *s;
{
    int i;
    int notified = 0;
    struct macros *m;
    char *unparse;

    for (i = 0; i < nummacros; i++) {
	m = macros[i];

	if (can_read_macros(player, m)) {
	    if (!notified) {
		notify(player,
		    "Num  Description                         Owner                     LRW");
		notified = 1;
	    }
	    unparse = unparse_object(player, m->player, 0);
	    notify(player, tprintf("%-4d %-35.35s %-24.24s  %c%c%c", i,
		    m->desc, unparse, m->status & MACRO_L ? 'L' : '-',
		    m->status & MACRO_R ? 'R' : '-',
		    m->status & MACRO_W ? 'W' : '-'));
	    free_lbuf(unparse);
	}
    }

    if (!notified)
	notify(player, "MACRO: There are no macro sets you can read.");
}

void do_add_macro(player, s)
dbref player;
char *s;
{
    int first;
    int set;
    struct macros *m;
    struct commac *c;
    int i;

    c = get_commac(player);

    first = -1;
    for (i = 0; i < 5 && first < 0; i++)
	if (c->macros[i] == -1)
	    first = i;

    if (first < 0) {
	notify(player,
	    "MACRO: Sorry, you already have 5 sets defined on you.");
    } else if (is_number(s)) {
	set = atoi(s);
	if (set >= 0 && set < nummacros) {
	    m = macros[set];
	    if (can_read_macros(player, m)) {
		c->macros[first] = set;
		notify(player,
		    tprintf("MACRO: Macro set %d added in the %d slot.",
			set, first));
	    } else {
		notify(player, "MACRO: Permission denied.");
	    }
	} else {
	    notify(player, "MACRO: That macro set does not exist.");
	    return;
	}
    } else {
	notify(player,
	    "MACRO: What set do you want to add to your macro system?");
    }
}

void do_del_macro(player, s)
dbref player;
char *s;
{
    struct commac *c;
    int set;

    c = get_commac(player);

    if (is_number(s)) {
	set = atoi(s);
	if (set >= 0 && set < 5 && c->macros[set] >= 0) {
	    c->macros[set] = -1;
	    notify(player, tprintf("MACRO: Macro slot %d cleared.", set));
	    if (set == c->curmac) {
		c->curmac = -1;
		notify(player,
		    "MACRO: Deleted current slot, resetting to none.");
	    }
	} else
	    notify(player, "MACRO: That is not a legal macro slot.");
    } else
	notify(player,
	    "MACRO: What set did you want to delete from your macro system?");
}

void do_desc_macro(player, s)
dbref player;
char *s;
{
    struct macros *m;

    m = get_macro_set(player, -1);
    if (m) {
	free(m->desc);
	m->desc = (char *) malloc(strlen(s) + 1);
	StringCopy(m->desc, s);
	notify(player, tprintf("MACRO: Current slot description to %s.",
		s));
    } else
	notify(player, "MACRO: You have no current slot set.");
}

void do_chmod_macro(player, s)
dbref player;
char *s;
{
    struct macros *m;
    int sign;

    m = get_macro_set(player, -1);

    if (m) {
	if ((m->player != player) && !Wizard(player)) {
	    notify(player, "MACRO: Permission denied.");
	    return;
	}
	if (*s == '!') {
	    sign = 0;
	    s++;
	} else
	    sign = 1;

	switch (*s) {
	case 'L':
	case 'l':
	    if (sign) {
		m->status |= MACRO_L;
		notify(player,
		    "MACRO: Default Macro Slot is now locked and unwritable.");
	    } else {
		m->status &= ~MACRO_L;
		notify(player,
		    "MACRO: Default Macro Slot is now unlocked.");
	    }
	    break;
	case 'R':
	case 'r':
	    if (sign) {
		m->status |= MACRO_R;
		notify(player,
		    "MACRO: Default Macro Slot set to be readable by others");
	    } else {
		m->status &= ~MACRO_R;
		notify(player,
		    "MACRO: Default Macro Slot set to be not readable by others");
	    }
	    break;
	case 'W':
	case 'w':
	    if (sign) {
		m->status |= MACRO_W;
		notify(player,
		    "MACRO: Default Macro Slot set to be writable by others");
	    } else {
		m->status &= ~MACRO_W;
		notify(player,
		    "MACRO: Default Macro Slot set to be not writable by others");
	    }
	    break;
	default:
	    notify(player,
		"MACRO: Sorry, unknown mode.  Legal modes are: L R W");
	}
    } else
	notify(player, "MACRO: You have no current slot set.");
}

void do_gex_macro(player, s)
dbref player;
char *s;
{
    struct macros *m;
    int which;
    int i;
    char buffer[LBUF_SIZE];

    if (!s || !*s) {
	notify(player, "MACRO: You need to specify a macro set.");
	return;
    }
    if (is_number(s)) {
	which = atoi(s);
	if ((which >= nummacros) || (which < 0) || (nummacros == 0)) {
	    notify(player,
		tprintf
		("MACRO: Illegal Macro Set.  Macros go from 0 to %d.",
		    nummacros - 1));
	    return;
	} else
	    m = macros[which];
    } else {
	notify(player, "MACRO: I do not see that set here.");
	return;
    }

    if (m && can_read_macros(player, m)) {
	notify(player, tprintf("Macro Definitions for %s", m->desc));
	for (i = 0; i < m->nummacros; i++) {
	    sprintf(buffer, "  %-5.5s: %s", m->alias + i * 5,
		m->string[i]);
	    notify(player, buffer);
	}
    } else
	notify(player, "MACRO: Permission denied.");

}

void do_edit_macro(player, s)
dbref player;
char *s;
{
    struct commac *c;
    int set;

    c = get_commac(player);

    if (is_number(s)) {
	set = atoi(s);
	if (set >= 0 && set < 5 && GMac(c->macros[set])) {
	    c->curmac = set;
	    notify(player, tprintf("MACRO: Current slot set to %d.", set));
	} else
	    notify(player, "MACRO: That is not a legal macro slot.");
    } else
	notify(player, "MACRO: What slot did you want to make current?");
}

void do_status_macro(player, s)
dbref player;
char *s;
{
    int i;
    struct commac *c;
    struct macros *m;
    char *unparse;

    c = get_commac(player);

    notify(player,
	"#: Num  Description                         Owner                     LRW");
    for (i = 0; i < 5; i++) {
	if (c->macros[i] >= 0)
	    if (!(GMac(c->macros[i])))
		notify(player, tprintf("%d: INVALID MACRO SET!", i));
	    else {
		m = macros[c->macros[i]];
		unparse = unparse_object(player, m->player, 0);
		notify(player,
		    tprintf("%d: %-4d %-35.35s %-24.24s  %c%c%c", i,
			c->macros[i], m->desc, unparse,
			m->status & MACRO_L ? 'L' : '-',
			m->status & MACRO_R ? 'R' : '-',
			m->status & MACRO_W ? 'W' : '-'));
		free_lbuf(unparse);
	} else
	    notify(player, tprintf("%d:", i));
    }
    notify(player, tprintf("Current Macro Slot: %d", c->curmac));
}

void do_ex_macro(player, s)
dbref player;
char *s;
{
    struct macros *m;
    int which;
    int i;
    char buffer[LBUF_SIZE];

    if (is_number(s)) {
	which = atoi(s);
	m = get_macro_set(player, which);
    } else
	m = get_macro_set(player, -1);

    if (m) {
	notify(player, tprintf("Macro Definitions for %s", m->desc));
	for (i = 0; i < m->nummacros; i++) {
	    sprintf(buffer, "  %-5.5s: %s", m->alias + i * 5,
		m->string[i]);
	    notify(player, buffer);
	}
    } else
	notify(player, "MACRO: Illegal macro set to examine.");

}

void do_chown_macro(player, cmd)
dbref player;
char *cmd;
{
    struct macros *m;
    dbref thing;
    char *unparse;

    m = get_macro_set(player, -1);
    thing = match_thing(player, cmd);

    if (thing == NOTHING) {
	notify(player, "MACRO: I do not see that here.");
	return;
    }
#if 0
    if (!m || !can_write_macros(player, m)) {
	notify(player, "MACRO: Permission denied.");
    }
#endif
    if (!m) {
	notify(player, "MACRO: No current active macro.");
	return;
    }
    if (!Wizard(player)) {
	notify(player, "MACRO: Sorry, command limited to Wizards.");
	return;
    }
    m->player = thing;
    unparse = unparse_object(player, thing, 0);
    notify(player, tprintf("MACRO: Macro %s chowned to %s.", m->desc,
	    unparse));
    free_lbuf(unparse);
}

static void clear_macro_set(int set)
{
    struct macros *m;
    struct commac *c;
    int i, j;

    if (GMac(set)) {
	m = macros[set];
	for (i = 0; i < m->nummacros; i++) {
	    free(m->string[i]);
	}
	free(m->alias);
	free(m->string);
	free(m);

	nummacros--;
	for (i = set; i < nummacros; i++)
	    macros[i] = macros[i + 1];
	macros[i] = NULL;

    }
    for (i = 0; i < NUM_COMMAC; i++) {
	c = commac_table[i];
	while (c) {
	    for (j = 0; j < 5; j++) {
		if (c->macros[j] == set) {
		    c->macros[j] = -1;
		    if (c->curmac == j)
			c->curmac = -1;
		} else if (c->macros[j] > set) {
		    c->macros[j]--;
		}
	    }
	    c = c->next;
	}
    }
}

void do_clear_macro(player, s)
dbref player;
char *s;
{
    int set;
    struct macros *m;
    struct commac *c;

    c = get_commac(player);

    if (c->curmac == -1) {
	notify(player,
	    "MACRO: You are not currently editing a macro set.");
	return;
    } else if (c->macros[c->curmac] == -1) {
	notify(player, "MACRO: That is not a valid macro set.");
	return;
    }
    set = c->macros[c->curmac];
    m = macros[set];

    if (GMac(set)) {
	if ((player != m->player) && !Wizard(player)) {
	    notify(player,
		"MACRO: You may only CLEAR your own macro sets.");
	    return;
	} else if ((player == m->player) && (m->status & MACRO_L)) {
	    notify(player, "MACRO: Sorry, that macro set is locked.");
	    return;
	}
    }
    notify(player, tprintf("MACRO: Clearing macro set %d: %s.", set,
	    GMac(set) ? m->desc : "Nonexistent"));
    clear_macro_set(set);
}

void do_def_macro(player, cmd)
dbref player;
char *cmd;
{
    int i, j, where;
    struct macros *m;
    char *alias;
    char *s;
    char buffer[LBUF_SIZE];
    char **ns;
    char *na;

    m = get_macro_set(player, -1);

    if (!m) {
	notify(player, "MACRO: No current set.");
	return;
    }
    if (!can_write_macros(player, m)) {
	notify(player, "MACRO: Permission denied.");
	return;
    }
    for (alias = cmd; *alias && *alias == ' '; alias++)
	*alias = 0;

    cmd = alias;
    for (; *cmd && *cmd != ' ' && *cmd != '='; cmd++);
    while (*cmd && *cmd == ' ')
        *cmd++ = '\0';
    if (*cmd != '=') {
	notify(player,
	    "MACRO: You must specify an = in your macro definition");
	return;
    }
    *cmd++ = 0;
    while (*cmd && *cmd == ' ')
	*cmd++ = 0;

    s = cmd;

    if (!*s) {
	notify(player,
	    "MACRO: You must specify a string to substitute for.");
	return;
    } else if (strlen(alias) > 4) {
	notify(player, "MACRO: Please limit aliases to 4 chars or less.");
	return;
    }
    for (j = 0;
	j < m->nummacros && (strcasecmp(alias, m->alias + j * 5) > 0);
	j++);
    if (j < m->nummacros && !strcasecmp(alias, m->alias + j * 5)) {
	notify(player,
	    "MACRO: That alias is already defined in this set.");
	sprintf(buffer, "%-4.4s:%s", m->alias + j * 5, m->string[j]);
	notify(player, buffer);
	return;
    }
    if (m->nummacros >= m->maxmacros) {
	m->maxmacros += 10;
	na = (char *) malloc(5 * m->maxmacros);
	ns = (char **) malloc(sizeof(char *) * m->maxmacros);

	for (i = 0; i < m->nummacros; i++) {
	    StringCopy(na + i * 5, m->alias + i * 5);
	    ns[i] = m->string[i];
	}
	free(m->alias);
	free(m->string);
	m->alias = na;
	m->string = ns;
    }
    where = m->nummacros++;
    for (i = where; i > j; i--) {
	StringCopy(m->alias + i * 5, m->alias + (i - 1) * 5);
	m->string[i] = m->string[i - 1];
    }

    where = j;
    StringCopy(m->alias + where * 5, alias);
    m->string[where] = (char *) malloc(strlen(s) + 1);
    StringCopy(m->string[where], s);
    sprintf(buffer, "MACRO: Macro %s:%s defined.", alias, s);
    notify(player, buffer);
}

void do_undef_macro(player, cmd)
dbref player;
char *cmd;
{
    int i;
    struct macros *m;

    m = get_macro_set(player, -1);

    if (!m || !can_write_macros(player, m)) {
	notify(player, "MACRO: Permission denied.");
	return;
    }
    for (i = 0; i < m->nummacros; i++) {
	if (!strcmp(m->alias + i * 5, cmd)) {
	    free(m->string[i]);
	    m->nummacros--;
	    for (; i < m->nummacros; i++) {
		StringCopy(m->alias + i * 5, m->alias + i * 5 + 5);
		m->string[i] = m->string[i + 1];
	    }
	    notify(player, "MACRO: Macro deleted from set.");
	    return;
	}
    }
    notify(player, "MACRO: That macro is not in this set.");
}

char *do_process_macro(player, in, s)
dbref player;
char *in;
char *s;
{
    char *cmd;
    char *tar;
    char *next;
    struct macros *m;
    int first, last, current = 0;
    int dir;
    int i;
    struct commac *c;
    char *buff;

    c = get_commac(player);
    buff = alloc_lbuf("do_process_macro");
    cmd = in + 1;
    buff[0] = '\0';		/*
				 * End the string 
				 */
    for (i = 0; i < 5; i++) {
	if (GMac(c->macros[i])) {
	    m = macros[c->macros[i]];
	    if (m->nummacros > 0) {
		first = 0;
		last = m->nummacros - 1;
		dir = 1;
		next = in + 1;
		while (dir && (first <= last)) {
		    current = (first + last) / 2;
		    dir = strcmp(next, m->alias + 5 * current);
		    if (dir < 0)
			last = current - 1;
		    else
			first = current + 1;
		}

		if (!dir) {
		    tar = m->string[current];
#if 1				/* Original MUSE code */
		    next = buff;
		    while (*tar) {
			if (*tar == '%' && *(tar + 1) == '*') {
			    *next++ = '*';
			    tar += 2;
			} else if (*tar == '*') {
			    *next = 0;
			    strcat(next, s);
			    tar++;
			    next += strlen(next);
			} else
			    *next++ = *tar++;
		    }
		    *next = 0;
#else
		    while (*tar) {
			switch (*tar) {
			case '*':
			    if (!buff)
				StringCopy(buff, s);
			    else
				strcat(buff, s);
			    break;
			case '%':
			    if (!buff)
				StringCopy(buff, tar + 1);
			    else
				sprintf(buff, "%s%c", buff, tar + 1);
			    *tar++;
			    break;
			default:
			    if (!buff)
				StringCopy(buff, tar);
			    else
				sprintf(buff, "%s%c", buff, *tar);
			    break;
			}
			*tar++;
		    }
#endif
		    return buff;
		}
	    }
	}
    }
    free_lbuf(buff);
    return NULL;
}

struct macros *get_macro_set(player, which)
dbref player;
int which;
{
    int set;
    struct commac *c;

    c = get_commac(player);

    if (c) {
	set = -1;
	if (which >= 0 && which < 5)
	    set = c->macros[which];
	else if (c->curmac >= 0)
	    set = c->macros[c->curmac];

	if (set == -1)
	    return NULL;
	else
	    return macros[set];
    } else
	return NULL;
}

void do_sort_macro_set(m)
struct macros *m;
{
    int i;
    int cont;
    char buffer[10];
    char *s;

    cont = 1;
    while (cont) {
	cont = 0;
	for (i = 0; i < m->nummacros - 1; i++)
	    if (strcasecmp(m->alias + i * 5, m->alias + (i + 1) * 5) > 0) {
		StringCopy(buffer, m->alias + i * 5);
		StringCopy(m->alias + i * 5, m->alias + (i + 1) * 5);
		StringCopy(m->alias + (i + 1) * 5, buffer);
		s = m->string[i];
		m->string[i] = m->string[i + 1];
		m->string[i + 1] = s;
		cont = 1;
	    }
    }
}

void do_create_macro(player, s)
dbref player;
char *s;
{
    int first;
    int i;
    struct commac *c;
    struct macros **nm;
    int set;

    c = get_commac(player);
    first = -1;
    for (i = 0; i < 5 && first < 0; i++)
	if (c->macros[i] == -1)
	    first = i;
    if (first < 0) {
	notify(player,
	    "MACRO: Sorry, you already have 5 sets defined on you.");
	return;
    }
    if (nummacros >= maxmacros) {
	maxmacros += 10;
	nm = (struct macros **) malloc(sizeof(struct macros *) *
	    maxmacros);

	for (i = 0; i < nummacros; i++)
	    nm[i] = macros[i];
	free(macros);
	macros = nm;
    }
    set = nummacros++;
    macros[set] = (struct macros *) malloc(sizeof(struct macros));

    macros[set]->player = player;
    macros[set]->status = 0;
    macros[set]->nummacros = 0;
    macros[set]->maxmacros = 0;
    macros[set]->alias = NULL;
    macros[set]->string = NULL;
    macros[set]->desc = (char *) malloc(strlen(s) + 1);
    StringCopy(macros[set]->desc, s);
    c->curmac = first;
    c->macros[first] = set;

    notify(player,
	tprintf("MACRO: Macro set %d created with description %s.", set,
	    s));
}

int can_write_macros(player, m)
dbref player;
struct macros *m;
{
    if (m->status & MACRO_L)
	return 0;

    if (m->player == player)
	return 1;
    else
	return m->status & MACRO_W;
}

int can_read_macros(player, m)
dbref player;
struct macros *m;
{
    if (Wizard(player))
	return 1;

    if (!m)
	return 0;

    if (m->player == player)
	return 1;
    else
	return m->status & MACRO_R;
}

#define TST(cmd,msg) if (cmd) { fprintf(stderr, msg); exit(1); }

void load_macros(fp)
FILE *fp;
{
    int i, j;
    char *c;
    char *t;
    char buffer[LBUF_SIZE];
    struct macros *m;

    TST(fscanf(fp, "%d\n", &nummacros) != 1, "Error: Loading #macros\n");
    maxmacros = nummacros;

    if (maxmacros > 0)
	macros =
	    (struct macros **) malloc(sizeof(struct macros *) * nummacros);
    else
	macros = NULL;

    for (i = 0; i < nummacros; i++) {
	macros[i] = (struct macros *) malloc(sizeof(struct macros));

	m = macros[i];

	fgets(buffer, LBUF_SIZE, fp);
	TST(sscanf(buffer, "%d %d %d\n", &(m->player), &(m->nummacros), &j)
	    != 3, tprintf("Reading macro set #%d\n", i));
	m->status = j;

	fgets(buffer, LBUF_SIZE, fp);
	if (*buffer)
	    if (buffer[strlen(buffer) - 1] == '\n')
		buffer[strlen(buffer) - 1] = 0;

	m->desc = (char *) malloc(strlen(buffer) - 1);
	StringCopy(m->desc, buffer + 2);

	m->maxmacros = m->nummacros;
	if (m->nummacros > 0) {
	    m->alias = (char *) malloc(5 * m->maxmacros);
	    m->string = (char **) malloc(sizeof(char *) * m->nummacros);

	    for (j = 0; j < m->nummacros; j++) {
		t = m->alias + j * 5;
		fgets(buffer, LBUF_SIZE, fp);
		if (buffer[strlen(buffer) - 1] == '\n')
		    buffer[strlen(buffer) - 1] = 0;
		for (c = buffer; *c && *c != ' '; c++);
		*c = 0;
		if (strlen(buffer) > 4) {
		    fprintf(stderr, "Error reading macro set #%d!\n", i);
		    exit(1);
		}
		if (!*buffer) {

/* fprintf(stderr, "Error in macro set #%d (macro %d) : Invalid macro name.\n", i, j); */
		    t[0] = 0;
		} else
		    strcpy(t, buffer);
		c++;
		m->string[j] = (char *) malloc(strlen(c) + 1);
		StringCopy(m->string[j], c);
	    }
	    do_sort_macro_set(m);
	} else {
	    m->alias = NULL;
	    m->string = NULL;
	}
    }
    while (1) {
	for (i = 0; i < nummacros; i++)
	    if (!isPlayer(macros[i]->player))
		break;
	if (i >= nummacros)
	    break;
	clear_macro_set(i);
    }
}

void save_macros(fp)
FILE *fp;
{
    int i, j;
    struct macros *m;

    fprintf(fp, "%d\n", nummacros);

    for (i = 0; i < nummacros; i++) {
	m = macros[i];
	fprintf(fp, "%d %d %d\n", m->player, m->nummacros,
	    (int) m->status);
	fprintf(fp, "D:%s\n", m->desc);
	for (j = 0; j < m->nummacros; j++)
	    fprintf(fp, "%s %s\n", m->alias + j * 5, m->string[j]);
    }
}