view 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 source

/* $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;
}