diff distress.c @ 3:5a977ccbc7a9 default tip

Empty changelog
author darius
date Sat, 06 Dec 1997 05:41:29 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/distress.c	Sat Dec 06 05:41:29 1997 +0000
@@ -0,0 +1,870 @@
+/* $Id: distress.c,v 1.1.1.1 1997/12/06 05:41:29 darius Exp $ */
+
+/*
+ * distress.c
+ */
+#include "copyright.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <ctype.h>
+#include <string.h>
+#ifndef SERVER
+#include "Wlib.h"
+#endif
+#include "defs.h"
+#include "struct.h"
+#include "data.h"
+#include "gameconf.h"
+#include "proto.h"
+
+/* #$!@$#% length of address field of messages */
+#define ADDRLEN 10
+#define MAXMACLEN 256
+#define MZERO bzero
+
+
+/*
+ * The two in-line defs that follow enable us to avoid calling strcat over
+ * and over again.
+ */
+char   *pappend;
+#define APPEND(ptr,str)     \
+   pappend = str;           \
+   while(*pappend)          \
+       *ptr++ = *pappend++;
+
+#define APPEND_CAP(ptr,cap,str) \
+   pappend = str;               \
+   while(*pappend)              \
+   {                            \
+       *ptr++ = (cap ? toupper(*pappend) : *pappend); \
+       pappend++;               \
+   }
+
+/*
+ * This is a hacked version from the K&R book.  Basically it puts <n> into
+ * <s> in reverse and then reverses the string...
+ * MH.  10-18-93
+ */
+int
+itoa2(n, s)
+    int     n;
+    char    s[];
+{
+    int     i, c, j, len;
+
+    if ((c = n) < 0)
+	n = -n;
+
+    i = 0;
+    do {
+	s[i++] = n % 10 + '0';
+    } while ((n /= 10) > 0);
+
+    if (c < 0)
+	s[i++] = '-';
+
+    s[i] = '\0';
+
+    len = i--;
+
+    for (j = 0; i > j; j++, i--) {
+	c = s[i];
+	s[i] = s[j];
+	s[j] = c;
+    }
+
+    return len;
+}
+
+/*
+ * Like APPEND, and APPEND_CAP, APPEND_INT is an in-line function that
+ * stops us from calling sprintf over and over again.
+ */
+#define APPEND_INT(ptr, i) \
+    ptr += itoa2(i, ptr);
+
+
+#ifdef SERVER
+#define ADDRLEN 10
+#define MAXMACLEN 85
+extern char *shiptypes[];
+#define warning(x)	fprintf(stderr,x)
+#endif
+
+
+char   *getaddr(), *getaddr2();
+
+
+
+/* This takes an MDISTR flagged message and makes it into a dist struct */
+void
+HandleGenDistr(message, from, to, dist)
+    char   *message;
+    struct distress *dist;
+    unsigned char from, to;
+{
+
+    char   *mtext;
+    unsigned char i;
+
+    mtext = &message[ADDRLEN];
+#ifndef SERVER
+    MZERO((char *) dist, sizeof(dist));
+#else
+    bzero((char *) dist, sizeof(dist));
+#endif
+
+    dist->sender = from;
+    dist->distype = mtext[0] & 0x1f;
+    dist->macroflag = ((mtext[0] & 0x20) > 0);
+    dist->fuelp = mtext[1] & 0x7f;
+    dist->dam = mtext[2] & 0x7f;
+    dist->shld = mtext[3] & 0x7f;
+    dist->etmp = mtext[4] & 0x7f;
+    dist->wtmp = mtext[5] & 0x7f;
+    dist->arms = mtext[6] & 0x1f;
+    dist->sts = mtext[7] & 0x7f;
+    dist->wtmpflag = ((dist->sts & PFWEP) != 0) ? 1 : 0;
+    dist->etempflag = ((dist->sts & PFENG) != 0) ? 1 : 0;
+    dist->cloakflag = ((dist->sts & PFCLOAK) != 0) ? 1 : 0;
+    dist->close_pl = mtext[8] & 0x7f;
+    dist->close_en = mtext[9] & 0x7f;
+    dist->tclose_pl = mtext[10] & 0x7f;
+    dist->tclose_en = mtext[11] & 0x7f;
+    dist->tclose_j = mtext[12] & 0x7f;
+    dist->close_j = mtext[13] & 0x7f;
+    dist->tclose_fr = mtext[14] & 0x7f;
+    dist->close_fr = mtext[15] & 0x7f;
+    i = 0;
+    while ((mtext[16 + i] & 0xc0) == 0xc0 && (i < 6)) {
+	dist->cclist[i] = mtext[16 + i] & 0x1f;
+	i++;
+    }
+    dist->cclist[i] = mtext[16 + i];
+    if (dist->cclist[i] == 0x80)
+	dist->pre_app = 1;
+    else
+	dist->pre_app = 0;
+    dist->preappend[0] = '\0';
+
+    if (mtext[16 + i + 1] != '\0') {
+	strncpy(dist->preappend, &mtext[16 + i + 1], MSG_LEN - 1);
+	dist->preappend[MSG_LEN - 1] = '\0';
+    }
+}
+
+/* this converts a dist struct to the appropriate text
+   (excludes F1->FED text bit).. sorry if this is not what we said
+   earlier jeff.. but I lost the paper towel I wrote it all down on */
+void
+Dist2Mesg(dist, buf)
+    struct distress *dist;
+    char   *buf;
+{
+    int     len, i;
+
+    sprintf(buf, "%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
+	    (dist->macroflag << 5) + (dist->distype),
+	    dist->fuelp | 0x80,
+	    dist->dam | 0x80,
+	    dist->shld | 0x80,
+	    dist->etmp | 0x80,
+	    dist->wtmp | 0x80,
+	    dist->arms | 0x80,
+	    dist->sts | 0x80,
+	    dist->close_pl | 0x80,
+	    dist->close_en | 0x80,
+	    dist->tclose_pl | 0x80,
+	    dist->tclose_en | 0x80,
+	    dist->tclose_j | 0x80,
+	    dist->close_j | 0x80,
+	    dist->tclose_fr | 0x80,
+	    dist->close_fr | 0x80);
+
+    /* cclist better be terminated properly otherwise we hose here */
+    i = 0;
+    while (((dist->cclist[i] & 0xc0) == 0xc0)) {
+	buf[16 + i] = dist->cclist[i];
+	i++;
+    }
+    /* get the pre/append cclist terminator in there */
+    buf[16 + i] = dist->cclist[i];
+    buf[16 + i + 1] = '\0';
+
+    len = 16 + i + 1;
+    if (dist->preappend[0] != '\0') {
+	strncat(buf, dist->preappend, MSG_LEN - len);	/* false sense of
+							   security? */
+	buf[MSG_LEN - 1] = '\0';
+    }
+}
+
+/* small permutation on the newmacro code... this takes a pointer to
+   ** a distress structure and a pointer to a macro syntax string,
+   ** and converts it into a line of text.
+   **  9/1/93 - jn
+ */
+int
+makedistress(dist, cry, pm)
+    struct distress *dist;	/* the info */
+    char   *cry;		/* the call for help! (output) - should be
+				   array */
+    char   *pm;			/* macro to parse, used for distress and
+				   macro */
+{
+    char    buf1[10 * MAXMACLEN];
+    char   *pbuf1;
+    char    buf2[10 * MAXMACLEN];
+    char    buf3[10 * MAXMACLEN];
+    char    tmp[10 * MAXMACLEN];
+    int     index = 0;
+    int     index2 = 0;
+    int     index3 = 0;
+    int     cap = 0;
+    struct player *sender;
+    struct player *j;
+    struct planet *l;
+    char   *strcap();
+#ifndef SERVER
+    extern int ping_tloss_sc;	/* total % loss 0--100, server to client */
+    extern int ping_tloss_cs;	/* total % loss 0--100, client to server */
+    extern int ping_av;		/* average rt */
+    extern int ping_sd;		/* standard deviation */
+#endif
+    char    c;
+
+
+    sender = &players[dist->sender];
+
+    if (!(*pm)) {
+	cry[0] = '\0';
+	return (0);
+    }
+    buf1[0] = '\0';
+    pbuf1 = buf1;
+
+    /* first step is to substitute variables */
+    while (*pm) {
+	if (*pm == '%') {
+	    pm++;
+
+	    if (!pm)
+		continue;
+
+	    switch (c = *(pm++)) {
+	    case ' ':
+		APPEND(pbuf1, " \0");
+		break;
+	    case 'O':		/* push a 3 character team name into buf */
+		cap = 1;
+	    case 'o':		/* push a 3 character team name into buf */
+		APPEND_CAP(pbuf1, cap, teaminfo[sender->p_teami].shortname);
+		cap = 0;
+		break;
+	    case 'a':		/* push army number into buf */
+		APPEND_INT(pbuf1, dist->arms);
+		break;
+	    case 'd':		/* push damage into buf */
+		APPEND_INT(pbuf1, dist->dam);
+		break;
+	    case 's':		/* push shields into buf */
+		APPEND_INT(pbuf1, dist->shld);
+		break;
+	    case 'f':		/* push fuel into buf */
+		APPEND_INT(pbuf1, dist->fuelp);
+		break;
+	    case 'w':		/* push wtemp into buf */
+		APPEND_INT(pbuf1, dist->wtmp);
+		break;
+	    case 'e':		/* push etemp into buf */
+		APPEND_INT(pbuf1, dist->etmp);
+		break;
+
+	    case 'P':		/* push player id into buf */
+	    case 'G':		/* push friendly player id into buf */
+	    case 'H':		/* push enemy target player id into buf */
+
+	    case 'p':		/* push player id into buf */
+	    case 'g':		/* push friendly player id into buf */
+	    case 'h':		/* push enemy target player id into buf */
+
+		switch (c) {
+		case 'p':
+		    j = &players[dist->tclose_j];
+		    break;
+		case 'g':
+		    j = &players[dist->tclose_fr];
+		    break;
+		case 'h':
+		    j = &players[dist->tclose_en];
+		    break;
+		case 'P':
+		    j = &players[dist->close_j];
+		    break;
+		case 'G':
+		    j = &players[dist->close_fr];
+		    break;
+		default:
+		    j = &players[dist->close_en];
+		    break;
+		}
+		tmp[0] = j->p_mapchars[1];
+		tmp[1] = '\0';
+		APPEND(pbuf1, tmp);
+		break;
+
+	    case 'n':		/* push planet armies into buf */
+		l = &planets[dist->tclose_pl];
+		APPEND_INT(pbuf1,
+			   ((l->pl_info & idx_to_mask(sender->p_teami))
+			    ? l->pl_armies : -1));
+		break;
+	    case 'B':
+		cap = 1;
+	    case 'b':		/* push planet into buf */
+		l = &planets[dist->close_pl];
+		tmp[0] = l->pl_name[0] - 'A' + 'a';
+		tmp[1] = l->pl_name[1];
+		tmp[2] = l->pl_name[2];
+		tmp[3] = '\0';
+		APPEND_CAP(pbuf1, cap, tmp);
+		cap = 0;
+		break;
+	    case 'L':
+		cap = 1;
+	    case 'l':		/* push planet into buf */
+		l = &planets[dist->tclose_pl];
+		tmp[0] = l->pl_name[0] - 'A' + 'a';
+		tmp[1] = l->pl_name[1];
+		tmp[2] = l->pl_name[2];
+		tmp[3] = '\0';
+		APPEND_CAP(pbuf1, cap, tmp);
+		cap = 0;
+		break;
+	    case 'Z':		/* push a 3 character team name into buf */
+		cap = 1;
+	    case 'z':		/* push a 3 character team name into buf */
+		l = &planets[dist->tclose_pl];
+		APPEND_CAP(pbuf1, cap,
+			   teaminfo[mask_to_idx(l->pl_owner)].shortname);
+		cap = 0;
+		break;
+	    case 't':		/* push a team character into buf */
+		l = &planets[dist->tclose_pl];
+		tmp[0] = teaminfo[mask_to_idx(l->pl_owner)].letter;
+		tmp[1] = '\0';
+		APPEND(pbuf1, tmp);
+		break;
+	    case 'T':		/* push my team into buf */
+		tmp[0] = teaminfo[sender->p_teami].letter;
+		tmp[1] = '\0';
+		APPEND(pbuf1, tmp);
+		break;
+	    case 'c':		/* push my id char into buf */
+		tmp[0] = sender->p_mapchars[1];
+		tmp[1] = '\0';
+		APPEND(pbuf1, tmp);
+		break;
+	    case 'W':		/* push WTEMP flag into buf */
+		if (dist->wtmpflag)
+		    tmp[0] = '1';
+		else
+		    tmp[0] = '0';
+		tmp[1] = '\0';
+		APPEND(pbuf1, tmp);
+		break;
+	    case 'E':		/* push ETEMP flag into buf */
+		if (dist->etempflag)
+		    tmp[0] = '1';
+		else
+		    tmp[0] = '0';
+		tmp[1] = '\0';
+		APPEND(pbuf1, tmp);
+		break;
+	    case 'K':
+		cap = 1;
+	    case 'k':
+		if (cap)
+		    j = &players[dist->tclose_en];
+		else
+		    j = sender;
+
+		if (j->p_ship->s_type == STARBASE)
+		    sprintf(tmp, "%5.2f", j->p_stats.st_sbkills / 100.0);
+		else
+		    sprintf(tmp, "%5.2f", (j->p_stats.st_kills + j->p_stats.st_tkills) / 100.0);
+		APPEND(pbuf1, tmp);
+		break;
+
+	    case 'U':		/* push player name into buf */
+		cap = 1;
+	    case 'u':		/* push player name into buf */
+		j = &players[dist->tclose_en];
+		APPEND_CAP(pbuf1, cap, j->p_name);
+		cap = 0;
+		break;
+	    case 'I':		/* my player name into buf */
+		cap = 1;
+	    case 'i':		/* my player name into buf */
+		APPEND_CAP(pbuf1, cap, sender->p_name);
+		cap = 0;
+		break;
+	    case 'S':		/* push ship type into buf */
+#ifndef SERVER
+		*pbuf1++ = sender->p_ship->s_desig[0];
+		*pbuf1++ = sender->p_ship->s_desig[1];
+#else
+		APPEND(pbuf1, shiptypes[sender->p_ship->s_type]);
+#endif
+		break;
+
+#ifdef SERVER
+	    case 'v':		/* push average ping round trip time into buf */
+	    case 'V':		/* push ping stdev into buf */
+	    case 'y':		/* push packet loss into buf */
+		APPEND(pbuf1, "0\0");
+	    case 'M':		/* push capitalized lastMessage into buf */
+	    case 'm':		/* push lastMessage into buf */
+		break;
+#else
+	    case 'M':		/* push capitalized lastMessage into buf */
+		cap = 1;
+	    case 'm':		/* push lastMessage into buf */
+		APPEND_CAP(pbuf1, cap, lastMessage);
+		cap = 0;
+		break;
+
+	    case 'v':		/* push average ping round trip time into buf */
+		APPEND_INT(pbuf1, ping_av);
+		break;
+
+	    case 'V':		/* push ping stdev into buf */
+		APPEND_INT(pbuf1, ping_sd);
+		break;
+
+	    case 'y':		/* push packet loss into buf */
+		/* this is the weighting formula used be socket.c ntserv */
+		APPEND_INT(pbuf1, (2 * ping_tloss_sc + ping_tloss_cs) / 3);
+		break;
+#endif
+
+	    case '*':		/* push %} into buf */
+		APPEND(pbuf1, "%*\0");
+		break;
+	    case '}':		/* push %} into buf */
+		APPEND(pbuf1, "%}\0");
+		break;
+	    case '{':		/* push %{ into buf */
+		APPEND(pbuf1, "%{\0");
+		break;
+	    case '!':		/* push %! into buf */
+		APPEND(pbuf1, "%!\0");
+		break;
+	    case '?':		/* push %? into buf */
+		APPEND(pbuf1, "%?\0");
+		break;
+	    case '%':		/* push %% into buf */
+		APPEND(pbuf1, "%%\0");
+		break;
+	    default:
+/* try to continue
+** bad macro character is skipped entirely,
+** the message will be parsed without whatever %. has occurred. - jn
+*/
+		warning("Bad Macro character in distress!");
+		fprintf(stderr, "Unrecognizable special character in distress pass 1: %c\n", *(pm - 1));
+		break;
+	    }
+	} else {
+	    tmp[0] = *pm;
+	    tmp[1] = '\0';
+	    APPEND(pbuf1, tmp);
+	    pm++;
+	}
+
+    }
+
+    *pbuf1 = '\0';
+
+    /* second step is to evaluate tests, buf1->buf2 */
+    testmacro(buf1, buf2, &index, &index2);
+    buf2[index2] = '\0';
+
+    if (index2 <= 0) {
+	cry[0] = '\0';
+	return (0);
+    }
+    index2 = 0;
+
+    /* third step is to include conditional text, buf2->buf3 */
+    condmacro(buf2, buf3, &index2, &index3, 1);
+
+    if (index3 <= 0) {
+	cry[0] = '\0';
+	return (0);
+    }
+    buf3[index3] = '\0';
+
+    cry[0] = '\0';
+    strncat(cry, buf3, MSG_LEN);
+
+    return (index3);
+}
+
+int
+testmacro(bufa, bufb, inda, indb)
+    char   *bufa;
+    char   *bufb;
+    int    *inda;
+    int    *indb;
+{
+    int     state = 0;
+
+    if (*indb >= 10 * MAXMACLEN)
+	return 0;
+/* maybe we should do something more "safe" here (and at other returns)? */
+
+
+    while (bufa[*inda] && (*indb < 10 * MAXMACLEN)) {
+	if (state) {
+	    switch (bufa[(*inda)++]) {
+	    case '*':		/* push %* into buf */
+		if (*indb < 10 * MAXMACLEN - 2) {
+		    bufb[*indb] = '%';
+		    (*indb)++;
+		    bufb[*indb] = '*';
+		    (*indb)++;
+		} else
+		    return (0);	/* we are full, so we are done */
+		state = 0;
+		continue;
+		break;
+
+	    case '%':		/* push %% into buf */
+		if (*indb < 10 * MAXMACLEN - 2) {
+		    bufb[*indb] = '%';
+		    (*indb)++;
+		    bufb[*indb] = '%';
+		    (*indb)++;
+		} else
+		    return (0);	/* we are full, so we are done */
+		state = 0;
+		continue;
+		break;
+
+	    case '{':		/* push %{ into buf */
+		if (*indb < 10 * MAXMACLEN - 2) {
+		    bufb[*indb] = '%';
+		    (*indb)++;
+		    bufb[*indb] = '{';
+		    (*indb)++;
+		} else
+		    return (0);	/* we are full, so we are done */
+		state = 0;
+		continue;
+		break;
+
+	    case '}':		/* push %} into buf */
+		if (*indb < 10 * MAXMACLEN - 2) {
+		    bufb[*indb] = '%';
+		    (*indb)++;
+		    bufb[*indb] = '}';
+		    (*indb)++;
+		} else
+		    return (0);	/* we are full, so we are done */
+		state = 0;
+		continue;
+		break;
+
+	    case '!':		/* push %! into buf */
+		if (*indb < 10 * MAXMACLEN - 2) {
+		    bufb[*indb] = '%';
+		    (*indb)++;
+		    bufb[*indb] = '!';
+		    (*indb)++;
+		} else
+		    return (0);	/* we are full, so we are done */
+		state = 0;
+		continue;
+		break;
+
+	    case '?':		/* the dreaded conditional, evaluate it */
+		bufb[*indb] = '0' + solvetest(bufa, inda);
+		(*indb)++;
+		state = 0;
+		continue;
+		break;
+
+	    default:
+		warning("Bad character in Macro!");
+		printf("Unrecognizable special character in macro pass2: %c  Trying to continue.\n",
+		       bufa[(*inda) - 1]);
+		state = 0;
+		continue;
+		break;
+	    }
+	}
+	if (bufa[*inda] == '%') {
+	    state++;
+	    (*inda)++;
+	    continue;
+	}
+	state = 0;
+
+
+	if (*indb < 10 * MAXMACLEN) {
+	    bufb[*indb] = bufa[*inda];
+	    (*inda)++;
+	    (*indb)++;
+	} else
+	    return (0);
+    }
+
+    return (0);
+}
+
+int
+solvetest(bufa, inda)
+    char   *bufa;
+    int    *inda;
+{
+    int     state = 0;
+    char    bufh[10 * MAXMACLEN];
+    char    bufc[10 * MAXMACLEN];
+    int     indh = 0, indc = 0, i;
+    char    operation;
+
+
+    while (bufa[*inda] &&
+	   bufa[*inda] != '<' &&
+	   bufa[*inda] != '>' &&
+	   bufa[*inda] != '=') {
+
+	bufh[indh++] = bufa[(*inda)++];
+    }
+    bufh[indh] = '\0';
+
+    operation = bufa[(*inda)++];
+
+    while (bufa[*inda] &&
+	   !(state &&
+	     ((bufa[*inda] == '?') ||
+	      (bufa[*inda] == '{')))) {
+
+	if (state && (bufa[*inda] == '%' ||
+		      bufa[*inda] == '!' ||
+		      bufa[*inda] == '}')) {
+	    bufc[indc++] = '%';
+	} else if (bufa[*inda] == '%') {
+	    state = 1;
+	    (*inda)++;
+	    continue;
+	}
+	state = 0;
+	bufc[indc++] = bufa[(*inda)++];
+    }
+    bufc[indc] = '\0';
+
+    if (bufa[*inda])
+	(*inda)--;
+
+    if (!operation)		/* incomplete is truth, just ask Godel */
+	return (1);
+
+    switch (operation) {
+    case '=':			/* character by character equality */
+	if (indc != indh)
+	    return (0);
+	for (i = 0; i < indc; i++) {
+	    if (bufc[i] != bufh[i])
+		return (0);
+	}
+	return (1);
+	break;
+
+    case '<':
+	if (atoi(bufh) < atoi(bufc))
+	    return (1);
+	else
+	    return (0);
+	break;
+
+    case '>':
+	if (atoi(bufh) > atoi(bufc))
+	    return (1);
+	else
+	    return (0);
+	break;
+
+    default:
+	warning("Bad operation in Macro!");
+	printf("Unrecognizable operation in macro pass3: %c  Trying to continue.\n",
+	       operation);
+	return (1);		/* don't know what happened, pretend we do */
+	break;
+    }
+}
+
+int
+condmacro(bufa, bufb, inda, indb, flag)
+    char   *bufa;
+    char   *bufb;
+    int    *inda;
+    int    *indb;
+    int     flag;
+{
+    int     newflag, include;
+    int     state = 0;
+
+
+    if (*indb >= MAXMACLEN)
+	return 0;
+
+    include = flag;
+
+    while (bufa[*inda] && (*indb < MAXMACLEN)) {
+	if (state) {
+	    switch (bufa[(*inda)++]) {
+	    case '}':		/* done with this conditional, return */
+		return (0);
+		break;
+
+	    case '{':		/* handle new conditional */
+		if (*indb > 0) {
+		    (*indb)--;
+		    if (bufb[*indb] == '0')
+			newflag = 0;
+		    else
+			newflag = 1;
+		} else		/* moron starting with cond, assume true */
+		    newflag = 1;
+
+		if (include)
+		    condmacro(bufa, bufb, inda, indb, newflag);
+		else {
+		    (*indb)++;
+		    *inda = skipmacro(bufa, *inda);
+		}
+
+		state = 0;
+		continue;
+		break;
+
+	    case '!':		/* handle not indicator */
+		if (flag)
+		    include = 0;
+		else
+		    include = 1;
+
+		state = 0;
+		continue;
+		break;
+
+	    case '%':		/* push % into buf */
+		if (include) {
+		    if (*indb < MAXMACLEN) {
+			bufb[*indb] = '%';
+			(*indb)++;
+		    } else
+			return (0);
+		}
+		state = 0;
+		continue;
+
+	    default:
+		warning("Bad character in Macro!");
+		printf("Unrecognizable special character in macro pass4: %c  Trying to continue.\n",
+		       bufa[(*inda) - 1]);
+	    }
+	}
+	if (bufa[*inda] == '%') {
+	    state++;
+	    (*inda)++;
+	    continue;
+	}
+	state = 0;
+
+
+	if (include) {
+	    if (*indb < MAXMACLEN) {
+		bufb[*indb] = bufa[*inda];
+		(*inda)++;
+		(*indb)++;
+	    } else
+		return (0);
+	} else
+	    (*inda)++;
+    }
+    return (0);
+}
+
+int
+skipmacro(buf, index)
+    char    buf[];
+    int     index;
+{
+    int     state = 0;
+    int     end = 0;
+
+    if (index == 0)
+	index++;
+
+    while (buf[index] && !end) {
+	if (state) {
+	    switch (buf[index++]) {
+	    case '{':
+		index = skipmacro(buf, index);
+		continue;
+		break;
+	    case '}':
+		end = 1;
+		continue;
+		break;
+	    case '!':
+	    case '%':
+		state = 0;
+		continue;
+		break;
+	    default:
+		warning("Bad character in Macro!");
+		printf("Unrecognizable special character in macro pass5: %c  Trying to continue.\n",
+		       buf[index - 1]);
+	    }
+	}
+	if (buf[index] == '%') {
+	    state++;
+	    index++;
+	    continue;
+	}
+	state = 0;
+	index++;
+    }
+
+    return (index);
+}
+
+
+/* return a pointer to a capitalized copy of string s */
+char   *
+strcap(s)
+    char   *s;
+{
+    static char buf[256];	/* returns static */
+    register char *t = buf;
+
+    while (*s) {
+	if (islower(*s))
+	    *t++ = toupper(*s++);
+	else
+	    *t++ = *s++;
+    }
+    *t = 0;
+    if (buf[255]) {
+	fprintf(stderr, "ERROR: String constant overwritten\n");
+	return NULL;
+    }
+    return buf;
+}