/*
* MISC.C:
*
* Miscellaneous string, file and data structure manipulation
* routines.
*
* Copyright (C) 1991, 1992, 1993, 1997 Brooke Paul & Brett Vickers
*
*/
#ifdef IRIX
#define _BSD_COMPAT
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#endif /* IRIX */
#include "mstruct.h"
#include "mextern.h"
#include <stdio.h>
#include <sys/types.h>
#ifndef WIN32
#include <sys/time.h>
#else
#include <time.h>
#endif
#include <ctype.h>
#ifdef DMALLOC
#include "/usr/local/include/dmalloc.h"
#endif
/************************************************************************/
/* merror */
/************************************************************************/
/* merror is called whenever an error message should be output to the */
/* log file. If the error is fatal, then the program is aborted */
void merror(str, errtype)
char *str;
char errtype;
{
long t;
char bugstr[256];
t = time(0);
sprintf(bugstr, "Error occured in %s. %s", str, ctime(&t));
loge(bugstr);
if(errtype == FATAL)
exit(-1);
}
/************************************************************************/
/* lowercize */
/************************************************************************/
/* This function takes the string passed in as the first parameter and */
/* converts it to lowercase. If the flag in the second parameter has */
/* its first bit set, then the first letter is capitalized. */
void lowercize(str, flag)
char *str;
int flag;
{
int i, n;
n = (str) ? strlen(str) : 0;
for(i=0; i<n; i++)
str[i] = (str[i] >= 'A' && str[i] <= 'Z') ? str[i]+32:str[i];
if(flag & 1)
str[0] = (str[0] >= 'a' && str[0] <= 'z') ? str[0]-32:str[0];
}
/************************************************************************/
/* low */
/************************************************************************/
/* If the character passed in as the first parameter is an uppercase */
/* alphabetic character, then it is converted to lowercase and returned */
/* Otherwise, it is unchanged. */
int low(ch)
char ch;
{
if(ch >= 'A' && ch <= 'Z')
return(ch+32);
else
return(ch);
}
int up(ch)
char ch;
{
if(ch >= 'a' && ch <= 'z')
return(ch-32);
else
return(ch);
}
/************************************************************************/
/* zero */
/************************************************************************/
/* This function zeroes a block of bytes at the given pointer and the */
/* given length. */
void zero(ptr, size)
void *ptr;
int size;
{
char *chptr;
int i;
chptr = (char *)ptr;
for(i=0; i<size; i++)
chptr[i] = 0;
}
/* Temporary (but static) data for the next several functions */
static char xstr[5][80];
static int xnum=0;
/************************************************************************/
/* crt_str */
/************************************************************************/
/* This function takes the creature given it in the first parameter, */
/* and forms the appropriate singularized or pluralized version of the */
/* creature's name using certain flags. */
char *crt_str(crt, num, flag)
creature *crt;
int num, flag;
{
char ch;
char *str;
char pform[80];
char sform[80];
char pfile[80];
int found;
FILE *plural;
str = xstr[xnum]; xnum = (xnum + 1)%5;
if(crt->type != MONSTER) {
if((((F_ISSET(crt, PINVIS) || F_ISSET(crt, PDMINV)) &&
!(flag & 2)) || F_ISSET(crt, PDMINV)) && !F_ISSET(crt, PALIAS))
strcpy(str, "Someone");
else {
if(F_ISSET(crt, PALIAS) && F_ISSET(crt, PDMINV)) {
if(!F_ISSET(Ply[crt->fd].extr->alias_crt, MNOPRE)) {
strcpy(str, "A ");
strcat(str, Ply[crt->fd].extr->alias_crt->name);
}
else
strcpy(str, Ply[crt->fd].extr->alias_crt->name);
}
else
strcpy(str, crt->name);
if(F_ISSET(crt, PINVIS))
strcat(str, " (*)");
}
return(str);
}
if(num == 0) {
if(!F_ISSET(crt, MNOPRE)) {
strcpy(str, "the ");
strcat(str, crt->name);
}
else
strcpy(str, crt->name);
}
else if(num == 1) {
if(F_ISSET(crt, MNOPRE))
strcpy(str, "");
else {
ch = low(crt->name[0]);
if(ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' ||
ch == 'u')
strcpy(str, "an ");
else
strcpy(str, "a ");
}
strcat(str, crt->name);
}
else {
if(num < 21)
sprintf(str, "%s ", number[num]);
else
sprintf(str, "%d ", num);
strcat(str, crt->name);
if(F_ISSET(crt, MTOMEN)) {
str[strlen(str)-2] = 'e';
}
else if(!F_ISSET(crt, MDROPS)) {
str[strlen(str)+1] = 0;
str[strlen(str)+2] = 0;
if(str[strlen(str)-1] == 's' ||
str[strlen(str)-1] == 'x') {
str[strlen(str)] = 'e';
str[strlen(str)] = 's';
}
else
str[strlen(str)] = 's';
}
}
if(F_ISSET(crt, MIREGP) && num > 1)
{
found = 0;
strcpy(pfile, MONPATH);
strcat(pfile,"/plurals");
plural = fopen(pfile, "r");
if(plural != NULL)
{
while (!found && !(feof (plural)))
{
fflush(plural);
/* get singular form */
fgets(sform, sizeof(sform), plural);
sform[strlen(sform)-1] = 0;
fflush(plural);
/* get plural form */
fgets(pform, sizeof(pform), plural);
pform[strlen(pform)-1] = 0;
if(strcmp(crt->name, sform) == 0)
{
strcpy(str, "");
if(num < 21)
if(num < 21)
sprintf(str, "%s ", number[num]);
else
sprintf(str, "%d ", num);
strcat(str, pform);
found = 1;
}
}
fclose(plural);
}
}
if(flag & CAP)
str[0] = up(str[0]);
if((flag & MAG) && (crt->type != PLAYER) && (F_ISSET(crt, MMAGIC)))
strcat(str, " (M)");
return(str);
}
/************************************************************************/
/* obj_str */
/************************************************************************/
/* This function examines an object's flags and its name, and returns */
/* the appropriate pluralized or singularized version of the name. */
/* In some cases it is necessary to drop the s on a plural version of */
/* a word. */
char *obj_str(obj, num, flag)
object *obj;
int num, flag;
{
char ch;
char str2[10];
char *str;
char pform[80];
char sform[80];
char pfile[80];
int found;
FILE *plural;
str = xstr[xnum]; xnum = (xnum + 1)%5;
if(num == 0) {
if(!F_ISSET(obj, ONOPRE)) {
strcpy(str, "the ");
strcat(str, obj->name);
}
else
strcpy(str, obj->name);
}
else if(num == 1) {
if(F_ISSET(obj, ONOPRE) || obj->type == MONEY)
strcpy(str, "");
else if(F_ISSET(obj, OSOMEA))
strcpy(str, "some ");
else {
ch = low(obj->name[0]);
if(ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' ||
ch == 'u')
strcpy(str, "an ");
else
strcpy(str, "a ");
}
strcat(str, obj->name);
}
else {
if(num < 21)
sprintf(str, "%s ", number[num]);
else
sprintf(str, "%d ", num);
if(F_ISSET(obj, OSOMEA))
strcat(str, "sets of ");
strcat(str, obj->name);
if(!F_ISSET(obj, ODROPS) && !F_ISSET(obj, OSOMEA)) {
str[strlen(str)+1] = 0;
str[strlen(str)+2] = 0;
if(str[strlen(str)-1] == 's' ||
str[strlen(str)-1] == 'x') {
str[strlen(str)] = 'e';
str[strlen(str)] = 's';
}
else
str[strlen(str)] = 's';
}
}
if(F_ISSET(obj, OIREGP) && num > 1)
{
found = 0;
strcpy(pfile, OBJPATH);
strcat(pfile,"/plurals");
plural = fopen(pfile, "r");
if(plural != NULL)
{
while (!found && !(feof (plural)))
{
fflush(plural);
/* get singular form */
fgets(sform, sizeof(sform), plural);
sform[strlen(sform)-1] = 0;
fflush(plural);
/* get plural form */
fgets(pform, sizeof(pform), plural);
pform[strlen(pform)-1] = 0;
if(strcmp(obj->name, sform) == 0)
{
strcpy(str, "");
if(num < 21)
sprintf(str, "%s ", number[num]);
else
sprintf(str, "%d ", num);
strcat(str, pform);
found = 1;
}
}
fclose(plural);
}
}
if(flag & CAP)
str[0] = up(str[0]);
if((flag & MAG) && obj->adjustment) {
sprintf(str2, " (%s%d)", obj->adjustment >= 0 ? "+":"",
obj->adjustment);
strcat(str, str2);
}
else if((flag & MAG) && obj->magicpower)
strcat(str, " (M)");
return(str);
}
/************************************************************************/
/* delimit */
/************************************************************************/
/* This function takes a given string, and if it is greater than a given*/
/* number of characters, then it is split up into several lines. This */
/* is done by replacing spaces with carriage returns before the end of */
/* the line. */
#define MAXLINE 77
void delimit(str)
char *str;
{
int i, j, l, len, lastspace;
char str2[4096];
str2[0] = 0;
j = (str) ? strlen(str) : 0;
if(j < MAXLINE)
return;
len = 0; lastspace = -1; l = 0;
for(i=0; i<j; i++) {
if(str[i] == ' ')
lastspace = i;
if(str[i] == '\n') {
len = 0;
lastspace = -1;
}
len++;
if(len > MAXLINE && lastspace > -1) {
str[lastspace] = 0;
strcat(str2, &str[l]);
strcat(str2, "\n ");
l = lastspace + 1;
len = i - lastspace + 3;
lastspace = -1;
}
}
strcat(str2, &str[l]);
strcpy(str, str2);
}
/************************************************************************/
/* view_file */
/************************************************************************/
/* This function views a file whose name is given by the third */
/* parameter. If the file is longer than 20 lines, then the user is */
/* prompted to hit return to continue, thus dividing the output into */
/* several pages. */
#define FBUF 800
void view_file(fd, param, str)
int fd, param;
char *str;
{
char buf[FBUF+1];
int i, l, n, ff, line;
long offset;
buf[FBUF] = 0;
switch(param) {
case 1:
offset = 0L;
strcpy(Ply[fd].extr->tempstr[1], str);
ff = open(str, O_RDONLY, 0);
if(ff < 0) {
print(fd, "File could not be opened.\n");
RETURN(fd, command, 1);
}
line = 0;
while(1) {
n = read(ff, buf, FBUF);
l = 0;
for(i=0; i<n; i++) {
if(buf[i] == '\n') {
buf[i] = 0;
line++;
print(fd, "%s\n", &buf[l]);
offset += (i-l+1);
l = i+1;
}
if(line > 20) break;
}
if(line > 20) {
sprintf(Ply[fd].extr->tempstr[0], "%lu",
offset);
break;
}
else if(l != n) {
print(fd, "%s", &buf[l]);
offset += (i-l);
}
if(n<FBUF) break;
}
if(n==FBUF || line>20) {
F_SET(Ply[fd].ply, PREADI);
print(fd, "[Hit Return, Q to Quit]: ");
output_buf();
Ply[fd].io->intrpt &= ~1;
}
if(n<FBUF && line <= 20) {
close(ff);
RETURN(fd, command, 1);
}
else {
close(ff);
F_SET(Ply[fd].ply, PREADI);
RETURN(fd, view_file, 2);
}
case 2:
if(str[0] != 0) {
print(fd, "Aborted.\n");
F_CLR(Ply[fd].ply, PREADI);
RETURN(fd, command, 1);
}
offset = atol(Ply[fd].extr->tempstr[0]);
ff = open(Ply[fd].extr->tempstr[1], O_RDONLY, 0);
if(ff < 0) {
print(fd, "File could not be opened.\n");
F_CLR(Ply[fd].ply, PREADI);
RETURN(fd, command, 1);
}
lseek(ff, offset, 0);
line = 0;
while(1) {
n = read(ff, buf, FBUF);
l = 0;
for(i=0; i<n; i++) {
if(buf[i] == '\n') {
buf[i] = 0;
line++;
print(fd, "%s\n", &buf[l]);
offset += (i-l+1);
l = i+1;
}
if(line > 20) break;
}
if(line > 20) {
sprintf(Ply[fd].extr->tempstr[0], "%lu",
offset);
break;
}
else if(l != n) {
print(fd, "%s", &buf[l]);
offset += (i-l);
}
if(n<FBUF) break;
}
if(n==FBUF || line > 20) {
F_SET(Ply[fd].ply, PREADI);
print(fd, "[Hit Return, Q to Quit]: ");
output_buf();
Ply[fd].io->intrpt &= ~1;
}
if(n<FBUF && line <= 20) {
close(ff);
F_CLR(Ply[fd].ply, PREADI);
RETURN(fd, command, 1);
}
else {
close(ff);
RETURN(fd, view_file, 2);
}
}
}
/************************************************************************/
/* dice */
/************************************************************************/
/* This function rolls n s-sided dice and adds p to the total. */
int dice(n, s, p)
int n, s, p;
{
int i;
for(i=0; i<n; i++)
p += mrand(1,s);
return(p);
}
/************************************************************************/
/* exp_to_lev */
/************************************************************************/
/* This function takes a given amount of experience as its first */
/* argument returns the level that the experience reflects. */
int exp_to_lev(exp)
long exp;
{
int level = 1;
while (exp >= needed_exp[level-1] && level < MAXALVL)
level++;
if (level == MAXALVL) {
level = exp/(needed_exp[MAXALVL-1]);
level++;
level= MAX(25,level);
}
return(MAX(1,level));
}
/************************************************************************/
/* dec_daily */
/************************************************************************/
/* This function is called whenever a daily-use item or operation is */
/* used or performed. If the number of daily uses are used, up then */
/* a 0 is returned. Otherwise, the number of uses is decremented and */
/* a 1 is returned. */
int dec_daily(dly_ptr)
struct daily *dly_ptr;
{
long t;
struct tm *tm, time1, time2;
t = time(0);
tm = localtime(&t);
time1 = *tm;
tm = localtime(&dly_ptr->ltime);
time2 = *tm;
if(time1.tm_yday != time2.tm_yday) {
dly_ptr->cur = dly_ptr->max;
dly_ptr->ltime = t;
}
if(dly_ptr->cur == 0)
return(0);
dly_ptr->cur--;
return(1);
}
/************************************************************************/
/* loge */
/************************************************************************/
/* This function writes a formatted printf string to a logfile called */
/* "log" in the player directory. */
void loge(fmt, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10)
char *fmt;
int i1, i2, i3, i4, i5, i6, i7, i8, i9, i10;
{
char file[80];
char str[1024];
int fd;
sprintf(file, "%s/log", LOGPATH);
fd = open(file, O_RDWR, 0);
if(fd < 0) {
fd = open(file, O_RDWR | O_CREAT, ACC);
if(fd < 0) return;
}
lseek(fd, 0L, 2);
sprintf(str, fmt, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10);
write(fd, str, strlen(str));
close(fd);
}
/************************************************************************/
/* sort_cmds */
/************************************************************************/
/* This function sorts the global cmdlist structure array so that the */
/* command list is sorted by how often each command is used. The most- */
/* used commands will end up at the top of the list. */
void sort_cmds()
{
Cmdnum = 0;
while(cmdlist[Cmdnum].cmdno != 0) Cmdnum++;
qsort((void *)cmdlist, Cmdnum, sizeof(struct cmdstruct), sort_cmp);
}
/************************************************************************/
/* sort_cmp */
/************************************************************************/
/* This function is used by the quicksort routine to sort the command */
/* list according to how often each command has been used. */
int sort_cmp(arg1, arg2)
struct cmdstruct *arg1, *arg2;
{
return(strcmp(arg1->cmdstr, arg2->cmdstr));
}
/************************************************************************/
/* file_exists */
/************************************************************************/
/* This function returns 1 if the filename specified by the first par- */
/* ameter exists, 0 if it doesn't. */
int file_exists(filename)
char *filename;
{
int ff;
ff = open(filename, O_RDONLY);
if(ff > -1) {
close(ff);
return(1);
}
else
return(0);
}
/************************************************************************/
/* load_lockouts */
/************************************************************************/
/* This function opens the lockout file and reads in all locked out */
/* sites. */
void load_lockouts()
{
FILE *fp;
char str[80];
int i;
if(Lockout) free(Lockout);
Numlockedout = 0;
sprintf(str, "%s/lockout", LOGPATH);
fp = fopen(str, "r");
if(!fp) return;
while(1) {
if(fscanf(fp, "%s", str) == EOF) break;
if(fscanf(fp, "%s", str) == EOF) break;
if(fscanf(fp, "%s", str) == EOF) break;
Numlockedout++;
}
if(!Numlockedout) {
fclose(fp);
return;
}
Lockout = (lockout *)malloc(Numlockedout * sizeof(lockout));
fseek(fp, 0L, 0);
for(i=0; i<Numlockedout; i++) {
fscanf(fp, "%s", Lockout[i].userid);
fscanf(fp, "%s", Lockout[i].address);
fscanf(fp, "%s", Lockout[i].password);
if(Lockout[i].password[0] == '-' && !Lockout[i].password[1])
Lockout[i].password[0] = 0;
}
fclose(fp);
}
/************************************************************************/
/* please_wait */
/************************************************************************/
void please_wait(fd, duration)
int fd;
int duration;
{
if(duration == 1)
print(fd, "Please wait 1 more second.\n");
else
print(fd, "Please wait %d more seconds.\n", duration);
}
/************************************************************************/
/* logn */
/************************************************************************/
/* This function writes a formatted printf string to a logfile called */
/* "name" in the log directory. */
void logn(name,fmt, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10)
char *name;
char *fmt;
int i1, i2, i3, i4, i5, i6, i7, i8, i9, i10;
{
char file[80];
char str[1024];
int fd;
sprintf(file, "%s/%s", LOGPATH,name);
fd = open(file, O_RDWR | O_APPEND, 0);
if(fd < 0) {
fd = open(file, O_RDWR | O_CREAT, ACC);
if(fd < 0) return;
}
lseek(fd, 0L, 2);
sprintf(str, fmt, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10);
write(fd, str, strlen(str));
close(fd);
}
/*====================================================================*/
#ifdef FREEBSD
int is_num(str)
#else
int isnumber(str)
#endif
char *str;
/* checks if the given str contains all digits */
{
int len, i;
len = strlen(str);
for (i=0;i < len; i++)
if(!isdigit(str[i]))
return (0);
return (1);
}