On Thu, 4 Jan 2001, Brandon Allen wrote:
> i was going to move all the weather text and most of the other commen
> text in the mud out to text files in /lib/text so that it can be
> changed on the fly and reloaded i have seen manny things in the mud
> that i think it would be fun to have in a text file so that i could
> throw random stuff into it.
Moving the messages into a separately indexed file wouldn't be difficult.
A general approach that would meet your specifications but not be overly
flexible (that is, you couldn't use it to implement multi-language support
in your Mud [that's what GNU gettext is for, anyway]) or difficult to
implement would have the message file arranged as so:
<string key>~ <string>~
.
.
.
$~
This is easy to load using fread_string(). The file is over when you read
$ as a string key. While reading the file, build a hash table from it
using the string keys. The ELF hash function (taken from SVR4 binary file
specifications several years ago) will work well enough for us:
unsigned long hasher(const unsigned char *name)
{
unsigned long h = 0;
unsigned long g;
while (*name) {
h = (h << 4) + *(name++);
g = h & 0xF0000000;
if (g) h ^= g >> 24;
h &= ~g;
}
return h;
}
Now we write a function, "fetch_message()," which takes a string key,
looks it up in the hash function, and returns the proper message (or an
error string). E.g.,
const char *fetch_message(const unsigned char *key)
{
unsigned long k = hasher(key) % MESG_TABLE_SIZE;
struct str_list_node *stri;
for (stri = mesgHashTable[k]; stri; stri = stri->next)
if (k == stri->key)
break;
if (!stri) {
static char erbuf[MAX_STRING_LENGTH];
log("SYSERR: Invalid message key '%s'", key);
sprintf(erbuf, "ERROR! Please report this message to an admin:\r\n"
"Invalid message key '%s' requested.\r\n", key);
return ((const char *) erbuf);
}
return ((const char *) stri->string);
}
As you can see, this is fairly simple. I envision the hash table as using
linked lists for collision resolution. Building the hash table seems to
be pretty simple:
struct str_list_node
{
unsigned long key;
char *string;
struct str_list_node *next;
};
/*
* Only adjust MESG_TABLE_SIZE if you really understand hash tables and
* why 67 is the specific number chosen. I chose it because it's a
* prime number and, I think, high enough to prevent clustering and low
* enough to not waste memory. Your opinion, and mileage, may vary. As
* this is Mailer Code(tm), you might want to actually look into it to
* ensure I'm not out of my bloody mind.
*/
#define MESG_TABLE_SIZE 67
struct str_list_node *mesgHashTable[MESG_TABLE_SIZE];
void init_message_hash(void)
{
int i;
for (i = MESG_TABLE_SIZE-1; i >= 0; i--) mesgHashTable[i] = NULL;
}
/* Precondition: 'string' is an allocated string. */
void insert_message(const unsigned char *key, char *string)
{
unsigned long k = hasher(key)
unsigned long idx = k % MESG_TABLE_SIZE;
struct str_list_node *strn;
CREATE(strn, struct str_list_node, 1);
strn->key = k;
strn->string = string;
strn->next = mesgHashTable[idx];
mesgHashTable[idx] = strn;
}
Editing the message database is fairly simple, too, but I'll leave that as
an exercise to the reader. I think the above method would fit all of your
requirements and retain efficiency.
-dak
--
+---------------------------------------------------------------+
| FAQ: http://qsilver.queensu.ca/~fletchra/Circle/list-faq.html |
| Archives: http://post.queensu.ca/listserv/wwwarch/circle.html |
+---------------------------------------------------------------+
This archive was generated by hypermail 2b30 : 12/03/01 PST