/***************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* *
* In order to use any part of this Merc Diku Mud, you must comply with *
* both the original Diku license in 'license.doc' as well the Merc *
* license in 'license.txt'. In particular, you may not remove either of *
* these copyright notices. *
* *
* Much time and thought has gone into this software and you are *
* benefitting. We hope that you share your changes too. What goes *
* around, comes around. *
***************************************************************************/
#include <sys/types.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <memory.h>
#include "include.h"
extern int _filbuf args((FILE *));
/*
* Globals.
*/
char bug_buf[2 * MAX_INPUT_LENGTH];
char *help_greeting;
/*
* Locals.
*/
char *string_hash[MAX_KEY_HASH];
bool fBootDb;
char *string_space;
char *top_string;
char str_empty[1];
/*
* Memory management.
* Increase MAX_STRING if you have too.
* Tune the others only if you understand what you're doing.
*/
#define MAX_STRING 1348576
#define MAX_PERM_BLOCK 131072
#define MAX_MEM_TORLIST 11
void *rgFreeList[MAX_MEM_TORLIST];
const int rgSizeList[MAX_MEM_TORLIST] = {
16, 32, 64, 128, 256, 1024, 2048, 4096, 8192, 16384, 32768 - 64
};
int nAllocString;
int sAllocString;
int nAllocPerm;
int sAllocPerm;
/*
* Big mama top level function.
*/
void boot_db(void)
{
/*
* Init some data space stuff.
*/
{
if ((string_space = (char *) calloc(1, MAX_STRING)) == NULL)
exit(1);
top_string = string_space;
fBootDb = true;
}
fBootDb = false;
load_accnt_cmds();
load_greet();
//load_forums();
//load_notes();
return;
}
void load_greet()
{ FILE *fp;
char buf[MSL];
sprintf(buf, "%sgreet.dat", DATA_DIR ); /* Greet is kept from a constant, cause may add random greets */
if( ( fp = fopen(buf, "r" ) ) != NULL)
{ SREAD(help_greeting);
return;
}
perror(buf);
exit(1); /* If the greeting isn't read, we'll shut her down! Cause, ya know, you can't run a mud without a greet! */
}
/*
* Allocate some ordinary memory,
* with the expectation of freeing it someday.
*/
void *alloc_mem(int sMem)
{
void *pMem;
int iList;
for (iList = 0; iList < MAX_MEM_TORLIST; iList++)
{
if (sMem <= rgSizeList[iList])
break;
}
if (iList == MAX_MEM_TORLIST)
{
exit(1);
}
if (rgFreeList[iList] == NULL)
{
pMem = alloc_perm(rgSizeList[iList]);
}
else
{
pMem = rgFreeList[iList];
rgFreeList[iList] = *((void **) rgFreeList[iList]);
}
return pMem;
}
/*
* Free some memory.
* Recycle it back onto the free list for blocks of that size.
*/
void free_mem(void *pMem, int sMem)
{
int iList;
for (iList = 0; iList < MAX_MEM_TORLIST; iList++)
{
if (sMem <= rgSizeList[iList])
break;
}
if (iList == MAX_MEM_TORLIST)
{
exit(1);
}
pMem = memset(pMem, 0, sMem);
*((void **) pMem) = rgFreeList[iList];
rgFreeList[iList] = pMem;
return;
}
/*
* Allocate some permanent memory.
* Permanent memory is never freed,
* pointers into it may be copied safely.
*/
void *alloc_perm(int sMem)
{
static char *pMemPerm;
static int iMemPerm;
void *pMem;
while (sMem % sizeof(long) != 0)
sMem++;
if (sMem > MAX_PERM_BLOCK)
{
exit(1);
}
if (pMemPerm == NULL || iMemPerm + sMem > MAX_PERM_BLOCK)
{
iMemPerm = 0;
if ((pMemPerm = (char *) calloc(1, MAX_PERM_BLOCK)) == NULL)
{
perror("Alloc_perm");
exit(1);
}
}
pMem = pMemPerm + iMemPerm;
iMemPerm += sMem;
nAllocPerm += 1;
sAllocPerm += sMem;
return pMem;
}
/*
* Duplicate a string into dynamic memory.
*/
char *str_dup(const char *str)
{
char *str_new;
if (str[0] == '\0')
return &str_empty[0];
if (str >= string_space && str < top_string)
return (char *) str;
str_new = (char *) alloc_mem(strlen(str) + 1);
strcpy(str_new, str);
return str_new;
}
/*
* Free a string.
* Null is legal here to simplify callers.
* Read-only shared strings are not touched.
*/
void free_string(char *pstr)
{
if (pstr == NULL
|| pstr == &str_empty[0]
|| (pstr >= string_space && pstr < top_string))
return;
free_mem(pstr, strlen(pstr) + 1);
return;
}
/*
* This function is here to aid in debugging.
* If the last expression in a function is another function call,
* gcc likes to generate a JMP instead of a CALL.
* This is called "tail chaining."
* It hoses the debugger call stack for that call.
* So I make this the last call in certain critical functions,
* where I really need the call stack to be right for debugging!
*
* If you don't understand this, then LEAVE IT ALONE.
* Don't remove any calls to tail_chain anywhere.
*
* -- Furey
*/
void tail_chain(void)
{
return;
}
/*
* Return true if an argument is completely numeric.
*/
bool is_number(char *arg)
{
if (*arg == '\0')
return false;
if (*arg == '+' || *arg == '-')
arg++;
for (; *arg != '\0'; arg++)
{
if (!isdigit(*arg))
return false;
}
return true;
}
/*
* Pick off one argument from a string and return the rest.
* Understands quotes.
*/
char *one_argument(char *argument, char *arg_first)
{
char cEnd;
while (isspace(*argument))
argument++;
cEnd = ' ';
if (*argument == '\'' || *argument == '"')
cEnd = *argument++;
while (*argument != '\0')
{
if (*argument == cEnd)
{
argument++;
break;
}
*arg_first = LOWER(*argument);
arg_first++;
argument++;
}
*arg_first = '\0';
while (isspace(*argument))
argument++;
return argument;
}
/* Thanks to ROM Here! Return FALSE if they match!*/
bool str_cmp( const char *astr, const char *bstr )
{
if ( astr == NULL )
return true;
if ( bstr == NULL )
return true;
for ( ; *astr || *bstr; astr++, bstr++ )
{ if ( LOWER(*astr) != LOWER(*bstr) )
return true;
}
return false;
}
/*
* Thanks to ROM here once again.
*/
bool str_prefix( const char *astr, const char *bstr )
{
if ( astr == NULL )
return true;
if ( bstr == NULL )
return true;
for ( ; *astr; astr++, bstr++ )
if ( LOWER(*astr) != LOWER(*bstr) )
return true;
return false;
}
/* Cudos to Rom again! */
char *fread_word( FILE *fp )
{
static char word[MAX_INPUT_LENGTH];
char *pword;
char cEnd;
do
{
cEnd = getc( fp );
}
while ( isspace( cEnd ) );
if ( cEnd == '\'' || cEnd == '"' )
{
pword = word;
}
else
{
word[0] = cEnd;
pword = word+1;
cEnd = ' ';
}
for ( ; pword < word + MAX_INPUT_LENGTH; pword++ )
{
*pword = getc( fp );
if ( cEnd == ' ' ? isspace(*pword) : *pword == cEnd )
{
if ( cEnd == ' ' )
ungetc( *pword, fp );
*pword = '\0';
return word;
}
}
exit( 1 );
return NULL;
}
/*
* Read and allocate space for a string from a file.
* These strings are read-only and shared.
* Strings are hashed:
* each string prepended with hash pointer to prev string,
* hash code is simply the string length.
* this function takes 40% to 50% of boot-up time.
*/
char *fread_string( FILE *fp )
{
char *plast;
char c;
plast = top_string + sizeof(char *);
if ( plast > &string_space[MAX_STRING - MAX_STRING_LENGTH] )
exit( 1 );
/*
* Skip blanks.
* Read first char.
*/
do
{
c = getc( fp );
}
while ( isspace(c) );
if ( ( *plast++ = c ) == '~' )
return &str_empty[0];
for ( ;; )
{
/*
* Back off the char type lookup,
* it was too dirty for portability.
* -- Furey
*/
switch ( *plast = getc(fp) )
{
default:
plast++;
break;
case EOF:
return NULL;
/* exit( 1 ); */
break;
case '\n':
plast++;
*plast++ = '\r';
break;
case '\r':
break;
case '~':
plast++;
{
union
{
char * pc;
char rgc[sizeof(char *)];
} u1;
int ic;
int iHash;
char *pHash;
char *pHashPrev;
char *pString;
plast[-1] = '\0';
iHash = UMIN( MAX_KEY_HASH - 1, plast - 1 - top_string );
for ( pHash = string_hash[iHash]; pHash; pHash = pHashPrev )
{
for ( ic = 0; ic < (int)sizeof(char *); ic++ )
u1.rgc[ic] = pHash[ic];
pHashPrev = u1.pc;
pHash += (int)sizeof(char *);
if ( top_string[sizeof(char *)] == pHash[0]
&& !strcmp( top_string+sizeof(char *)+1, pHash+1 ) )
return pHash;
}
if ( fBootDb )
{
pString = top_string;
top_string = plast;
u1.pc = string_hash[iHash];
for ( ic = 0; ic < (int)sizeof(char *); ic++ )
pString[ic] = u1.rgc[ic];
string_hash[iHash] = pString;
nAllocString += 1;
sAllocString += top_string - pString;
return pString + sizeof(char *);
}
else
{
return str_dup( top_string + sizeof(char *) );
}
}
}
}
}
int fread_number( FILE *fp )
{
int number;
bool sign;
char c;
do
{
c = getc( fp );
}
while ( isspace(c) );
number = 0;
sign = false;
if ( c == '+' )
{
c = getc( fp );
}
else if ( c == '-' )
{
sign = true;
c = getc( fp );
}
if ( !isdigit(c) )
exit( 1 );
while ( isdigit(c) )
{
number = number * 10 + c - '0';
c = getc( fp );
}
if ( sign )
number = 0 - number;
if ( c == '|' )
number += fread_number( fp );
else if ( c != ' ' )
ungetc( c, fp );
return number;
}
void fread_to_eol( FILE *fp )
{
char c;
do
{
c = getc( fp );
}
while ( c != '\n' && c != '\r' );
do
{
c = getc( fp );
}
while ( c == '\n' || c == '\r' );
ungetc( c, fp );
return;
}