/*************************************************************************** * 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 "merc.h" extern int _filbuf args((FILE *)); /* * Globals. */ CHAR_DATA *char_free; char bug_buf[2 * MAX_INPUT_LENGTH]; CHAR_DATA *char_list; char *help_greeting; /* * Locals. */ char *string_hash[MAX_KEY_HASH]; 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_LIST 11 void *rgFreeList[MAX_MEM_LIST]; const int rgSizeList[MAX_MEM_LIST] = { 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; } return; } /* * Clear a new character. */ void clear_char(CHAR_DATA * ch) { static CHAR_DATA ch_zero; *ch = ch_zero; ch->name = &str_empty[0]; ch->short_descr = &str_empty[0]; ch->long_descr = &str_empty[0]; ch->description = &str_empty[0]; return; } /* * Free a character. */ void free_char(CHAR_DATA * ch) { free_string(ch->name); free_string(ch->short_descr); free_string(ch->long_descr); free_string(ch->description); free_string(ch->pwd); ch->next = char_free; char_free = ch; return; } /* * 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_LIST; iList++) { if (sMem <= rgSizeList[iList]) break; } if (iList == MAX_MEM_LIST) { 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_LIST; iList++) { if (sMem <= rgSizeList[iList]) break; } if (iList == MAX_MEM_LIST) { 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; } /* * Extract a char from the world. */ void extract_char(CHAR_DATA * ch, bool fPull) { if (ch == char_list) { char_list = ch->next; } else { CHAR_DATA *prev; for (prev = char_list; prev != NULL; prev = prev->next) { if (prev->next == ch) { prev->next = ch->next; break; } } if (prev == NULL) { return; } } if (ch->desc) ch->desc->character = NULL; free_char(ch); return; }