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