Mercurial > ~darius > hgwebdir.cgi > paradise_client
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; +}