Re: FTP site and Ceramic Mouse

From: Daniel A. Koepke (dkoepke@circlemud.org)
Date: 01/05/01


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