Beispiel #1
0
/** Add new help command. This function is
 * the basis for the help_command directive in mush.cnf. It creates
 * a new help entry for the hash table, builds a help index,
 * and adds the new command to the command table.
 * \param command_name name of help command to add.
 * \param filename name of the help file to use for this command.
 * \param admin if 1, this command reads admin topics, rather than standard.
 */
void
add_help_file(const char *command_name, const char *filename, int admin)
{
  help_file *h;

  if (help_init == 0)
    init_help_files();

  if (!command_name || !filename || !*command_name || !*filename)
    return;

  /* If there's already an entry for it, complain */
  h = hashfind(strupper(command_name), &help_files);
  if (h) {
    do_rawlog(LT_ERR, "Duplicate help_command %s ignored.", command_name);
    return;
  }

  h = mush_malloc(sizeof *h, "help_file.entry");
  h->command = mush_strdup(strupper(command_name), "help_file.command");
  h->file = mush_strdup(filename, "help_file.filename");
  h->entries = 0;
  h->indx = NULL;
  h->admin = admin;
  help_build_index(h, h->admin);
  if (!h->indx) {
    mush_free(h->command, "help_file.command");
    mush_free(h->file, "help_file.filename");
    mush_free(h, "help_file.entry");
    return;
  }
  (void) command_add(h->command, CMD_T_ANY | CMD_T_NOPARSE, NULL, 0, NULL,
                     cmd_helpcmd);
  hashadd(h->command, h, &help_files);
}
Beispiel #2
0
/* Show the 'Obvious Exits' list for a room. Used in 'look' and 'examine'.
 * \param player The player looking
 * \param loc room whose exits we're showing
 * \param exit_name "Obvious Exits" string
 * \param pe_info the pe_info to use for evaluating EXITFORMAT and interact locks
 */
static void
look_exits(dbref player, dbref loc, const char *exit_name, NEW_PE_INFO *pe_info)
{
  dbref thing;
  char *tbuf1, *tbuf2, *nbuf;
  char *s1, *s2;
  char *p;
  int exit_count, this_exit, total_count;
  int texits;
  ufun_attrib ufun;
  PUEBLOBUFF;

  /* make sure location is a room */
  if (!IsRoom(loc))
    return;

  tbuf1 = (char *) mush_malloc(BUFFER_LEN, "string");
  tbuf2 = (char *) mush_malloc(BUFFER_LEN, "string");
  nbuf = (char *) mush_malloc(BUFFER_LEN, "string");
  if (!tbuf1 || !tbuf2 || !nbuf)
    mush_panic("Unable to allocate memory in look_exits");
  s1 = tbuf1;
  s2 = tbuf2;
  texits = exit_count = total_count = 0;
  this_exit = 1;

  if (fetch_ufun_attrib
      ("EXITFORMAT", loc, &ufun, UFUN_IGNORE_PERMS | UFUN_REQUIRE_ATTR)) {
    char *arg, *buff, *bp;
    PE_REGS *pe_regs = pe_regs_create(PE_REGS_ARG, "look_exits");

    arg = (char *) mush_malloc(BUFFER_LEN, "string");
    buff = (char *) mush_malloc(BUFFER_LEN, "string");
    if (!arg || !buff)
      mush_panic("Unable to allocate memory in look_exits");

    bp = arg;
    DOLIST(thing, Exits(loc)) {
      if (((Light(loc) || Light(thing)) || !(Dark(loc) || Dark(thing)))
          && can_interact(thing, player, INTERACT_SEE, pe_info)) {
        if (bp != arg)
          safe_chr(' ', arg, &bp);
        safe_dbref(thing, arg, &bp);
      }
    }
    *bp = '\0';
    pe_regs_setenv_nocopy(pe_regs, 0, arg);

    call_ufun(&ufun, buff, player, player, pe_info, pe_regs);

    pe_regs_free(pe_regs);
    notify_by(loc, player, buff);
    mush_free(tbuf1, "string");
    mush_free(tbuf2, "string");
    mush_free(nbuf, "string");
    mush_free(arg, "string");
    mush_free(buff, "string");
    return;
  }
Beispiel #3
0
/**
 * Free a ListTypeInfo struct.
 * \param lti The ListTypeInfo to free. Must be created by get_list_type_info.
 */
void
free_list_type_info(ListTypeInfo * lti)
{
  if (lti->attrname) {
    mush_free(lti->attrname, "list_type_info_attrname");
  }
  mush_free(lti, "list_type_info");
}
Beispiel #4
0
/** Free memory of a buffer queue.
 * \param bq pointer to buffer queue.
 */
void
free_bufferq(BUFFERQ *bq)
{
  if (!bq)
    return;
  if (bq->buffer)
    mush_free(bq->buffer, "bufferq.buffer");
  mush_free(bq, "bufferq");
}
Beispiel #5
0
static void
sitelock_free(struct access *ap)
{
  mush_free(ap->host, "sitelock.rule.pattern");
  if (ap->comment)
    mush_free(ap->comment, "sitelock.rule.comment");
  if (ap->re)
    free(ap);
  mush_free(ap, "sitelock.rule");
}
Beispiel #6
0
/**
 * Given an array of s_rec items, free them if they are not NULL.
 * \param sp the array of sort_records, returned by slist_build
 * \param n Number of items in <keys> and <strs>
 * \param lti List Type Info describing how it's sorted and built.
 */
void
slist_free(s_rec *sp, int n, ListTypeInfo * lti)
{
  int i;
  for (i = 0; i < n; i++) {
    if ((lti->flags & IS_STRING) && sp[i].memo.str.freestr)
      mush_free(sp[i].memo.str.s, "genrecord");
  }
  mush_free(sp, "do_gensort");
}
Beispiel #7
0
/** A generic comparer routine to compare two values of any sort type.
 * \param player Player doing the comparison
 * \param a Key 1 to compare
 * \param b Key 2 to compare
 * \param sort_type SortType describing what kind of comparison to make.
 */
int
gencomp(dbref player, char *a, char *b, SortType sort_type)
{
  char *ptr;
  int i, len;
  int result;
  s_rec s1, s2;
  ListTypeInfo *lti;
  ptr = NULL;
  if (!sort_type) {
    /* Advance i to the default */
    for (i = 0; ltypelist[i].name; i++) ;
  } else if ((ptr = strchr(sort_type, ':'))) {
    len = ptr - sort_type;
    ptr += 1;
    if (!*ptr)
      ptr = NULL;
    for (i = 0;
         ltypelist[i].name && strncasecmp(ltypelist[i].name, sort_type, len);
         i++) ;
  } else {
    for (i = 0; ltypelist[i].name && strcasecmp(ltypelist[i].name, sort_type);
         i++) ;
  }
  lti = get_list_type_info(sort_type);

  if (ltypelist[i].flags & IS_DB) {
    s1.db = parse_objid(a);
    s2.db = parse_objid(b);
    if (!RealGoodObject(s1.db))
      s1.db = NOTHING;
    if (!RealGoodObject(s2.db))
      s2.db = NOTHING;
  } else {
    s1.db = s2.db = 0;
  }

  s1.val = a;
  s2.val = b;
  genrecord(&s1, player, lti);
  genrecord(&s2, player, lti);
  result = lti->sorter((const void *) &s1, (const void *) &s2);
  if (lti->flags & IS_STRING) {
    if (s1.memo.str.freestr)
      mush_free(s1.memo.str.s, "genrecord");
    if (s2.memo.str.freestr)
      mush_free(s2.memo.str.s, "genrecord");
  }
  free_list_type_info(lti);
  return result;
}
Beispiel #8
0
/** Resize a hash table.
 * \param htab pointer to hashtable.
 * \param primesize new size.
 * \param hashindex Index of first hash function to use
 */
static bool
real_hash_resize(HASHTAB *htab, int newsize, int hashfunc_offset)
{
    HASHENT *oldarr;
    int oldsize, oldoffset, i;

    /* Massive overkill here */
    if (resize_calls > 150) {
        fputs("Ooops. Too many attempts to resize a hash table.\n", stderr);
        return false;
    }

    /* If all possible hash function combos have been exhausted,
       grow the array */
    if (hashfunc_offset == first_offset) {
        int newersize = next_prime_after(floor(newsize * 1.15));
        first_offset = -1;
        return real_hash_resize(htab, newersize, hashfunc_offset);
    }

    resize_calls += 1;

    /* Save the old data we need */
    oldsize = htab->hashsize;
    oldoffset = htab->hashfunc_offset;
    oldarr = htab->buckets;

    htab->buckets =
        mush_calloc(newsize, sizeof(struct hash_bucket), "hash.buckets");
    htab->hashsize = newsize;
    htab->hashfunc_offset = hashfunc_offset;
    for (i = 0; i < oldsize; i++) {
        if (oldarr[i].key) {
            if (!hash_insert(htab, oldarr[i].key, oldarr[i].keylen, oldarr[i].data)) {
                /* Couldn't fit an element in. Try with different hash functions. */
                mush_free(htab->buckets, "hash.buckets");
                htab->buckets = oldarr;
                htab->hashsize = oldsize;
                htab->hashfunc_offset = oldoffset;
                if (first_offset == -1)
                    first_offset = hashfunc_offset;
                return
                    real_hash_resize(htab, newsize, (hashfunc_offset + 1) % NHASH_MOD);
            }
        }
    }

    mush_free(oldarr, "hash.buckets");
    return true;
}
Beispiel #9
0
/** Flush a hash table, freeing all entries.
 * \param htab pointer to a hash table.
 * \param size size of hash table.
 */
void
hash_flush(HASHTAB *htab, int size)
{
    int i;
    struct hash_bucket *resized;

    if (htab->entries) {
        for (i = 0; i < htab->hashsize; i++) {
            if (htab->buckets[i].key) {
                mush_free((void *) htab->buckets[i].key, "hash.key");
                if (htab->free_data)
                    htab->free_data(htab->buckets[i].data);
            }
        }
    }
    htab->entries = 0;
    size = next_prime_after(size);
    resized =
        mush_realloc(htab->buckets, sizeof(struct hash_bucket) * size,
                     "hash.buckets");
    if (resized) {
        htab->buckets = resized;
        htab->hashsize = size;
    }
    memset(htab->buckets, 0, sizeof(struct hash_bucket) * htab->hashsize);
}
Beispiel #10
0
/** Return a list of all available locks
 * \param buff the buffer
 * \param bp a pointer to the current position in the buffer.
 * \param name if not NULL, only show locks with this prefix
 */
void
list_locks(char *buff, char **bp, const char *name)
{
  lock_list **locks, *lk;
  bool first = 1;
  int nlocks = 0, n;

  locks = mush_calloc(htab_locks.entries, sizeof(lock_list), "lock.list");

  for (lk = hash_firstentry(&htab_locks); lk; lk = hash_nextentry(&htab_locks)) {
    /* Skip those that don't match */
    if (name && !string_prefix(lk->type, name))
      continue;
    locks[nlocks++] = lk;
  }

  qsort(locks, nlocks, sizeof lk, lock_compare);

  for (n = 0; n < nlocks; n += 1) {
    if (first) {
      first = 0;
    } else {
      safe_chr(' ', buff, bp);
    }
    safe_str(strupper(locks[n]->type), buff, bp);
  }

  mush_free(locks, "lock.list");
}
Beispiel #11
0
/** Free all memory used by a standard attribute, and remove it from the hash
 * table if necessary.
 * \param a attr to remove
 * \param inserted has the attr been inserted into the hash table already?
 * \retval number of entries (including aliases) removed from the hash table
 */
static int
free_standard_attr(ATTR *a, bool inserted)
{
  int count = 0;
  if (!a) {
    return count;
  }

  /* If the attr has no name, there's no way it can be in the hash table */
  if (AL_NAME(a)) {
    if (inserted) {
      count = free_standard_attr_aliases(a) + 1;
      ptab_delete(&ptab_attrib, AL_NAME(a));
    }
    free((char *) AL_NAME(a));
  }

  if (a->data != NULL_CHUNK_REFERENCE) {
    chunk_delete(a->data);
  }

  mush_free(a, "ATTR");

  return count;

}
Beispiel #12
0
/**
 * Given an array of _sorted_ s_rec items, unique them in place by
 * freeing them and marking the final elements' freestr = 0.
 * \param sp the array of sort_records, returned by slist_build
 * \param n Number of items in <sp>
 * \param lti List Type Info describing how it's sorted and built.
 * \retval The count of unique items.
 */
int
slist_uniq(s_rec *sp, int n, ListTypeInfo * lti)
{
  int count, i;

  /* Quick sanity check. */
  if (n < 2)
    return n;

  /* First item's always 'unique' :D. */
  count = 1;

  for (i = 1; i < n; i++) {
    /* If sp[i] is a duplicate of sp[count - 1], free it. If it's not,
     * move it to sp[count] and increment count. */
    if (lti->sorter((const void *) &sp[count - 1], (const void *) &sp[i])) {
      /* Not a duplicate. */
      sp[count++] = sp[i];
    } else {
      /* Free it if needed. */
      if ((lti->flags & IS_STRING) && sp[i].memo.str.freestr) {
        mush_free(sp[i].memo.str.s, "genrecord");
      }
    }
  }
  for (i = count; i < n; i++) {
    if ((lti->flags & IS_STRING) && sp[i].memo.str.freestr) {
      sp[i].memo.str.freestr = 0;
      sp[i].memo.str.s = NULL;
    }
  }
  return count;
}
Beispiel #13
0
/** Deallocate an integer map. All data pointers that need to be freed
 *  qmust be deallocated seperately before this, or you'll get a memory
 *  leak.
 *  \param im the map to delete.
 */
void
im_destroy(intmap *im)
{
  if (im) {
    pat_destroy(im->root);
    mush_free(im, "int_map");
  }
}
Beispiel #14
0
static void
hash_delete_bucket(HASHTAB *htab, struct hash_bucket *entry)
{
  if (htab->free_data)
    htab->free_data(entry->data);
  mush_free((void *) entry->key, "hash.key");
  memset(entry, 0, sizeof *entry);
  htab->entries -= 1;
}
Beispiel #15
0
static void
delete_node(StrNode *node, const char *name)
{
  if (node->left)
    delete_node(node->left, name);
  if (node->right)
    delete_node(node->right, name);
  mush_free(node, name);
}
Beispiel #16
0
static void
delete_node(StrNode *node)
{
  if (node->left)
    delete_node(node->left);
  if (node->right)
    delete_node(node->right);
  mush_free(node, "StrNode");
}
Beispiel #17
0
/** Free a time zone description struct. */
void
free_tzinfo(struct tzinfo *tz)
{
  free(tz->transitions);
  free(tz->offset_indexes);
  free(tz->offsets);
  free(tz->leapsecs);
  free(tz->abbrevs);
  mush_free(tz, "timezone");
}
Beispiel #18
0
/** Delete an entry in a hash table.
 * \param htab pointer to hash table.
 * \param entry pointer to hash entry to delete (and free).
 */
void
hash_delete(HASHTAB *htab, HASHENT *entry)
{
    if (!entry)
        return;

    if (htab->free_data)
        htab->free_data(entry->data);
    mush_free((void *) entry->key, "hash.key");
    memset(entry, 0, sizeof *entry);
    htab->entries -= 1;
}
Beispiel #19
0
/** Add new help command. This function is
 * the basis for the help_command directive in mush.cnf. It creates
 * a new help entry for the hash table, builds a help index,
 * and adds the new command to the command table.
 * \param command_name name of help command to add.
 * \param filename name of the help file to use for this command.
 * \param admin if 1, this command reads admin topics, rather than standard.
 */
void
add_help_file(const char *command_name, const char *filename, int admin)
{
  help_file *h;
  char newfilename[256] = "\0";

  /* Must use a buffer for MacOS file path conversion */
  strncpy(newfilename, filename, 256);

  if (help_init == 0)
    init_help_files();

  if (!command_name || !filename || !*command_name || !*newfilename)
    return;

  /* If there's already an entry for it, complain */
  h = hashfind(strupper(command_name), &help_files);
  if (h) {
    do_rawlog(LT_ERR, T("Duplicate help_command %s ignored."), command_name);
    return;
  }

  h = mush_malloc(sizeof *h, "help_file.entry");
  h->command = mush_strdup(strupper(command_name), "help_file.command");
  h->file = mush_strdup(newfilename, "help_file.filename");
  h->entries = 0;
  h->indx = NULL;
  h->admin = admin;
  help_build_index(h, h->admin);
  if (!h->indx) {
    mush_free(h->command, "help_file.command");
    mush_free(h->file, "help_file.filename");
    mush_free(h, "help_file.entry");
    return;
  }
  (void) command_add(h->command, CMD_T_ANY | CMD_T_NOPARSE, NULL, cmd_helpcmd, NULL);
  hashadd(h->command, h, &help_files);
}
Beispiel #20
0
/** Rebuild a single help file index. Used in inotify reindexing.
 * \param filename the name of the help file to reindex.
 * \return true if a help file was reindexed, false otherwise.
 */
bool
help_reindex_by_name(const char *filename)
{
  help_file *curr;
  bool retval = 0;

  for (curr = hash_firstentry(&help_files);
       curr; curr = hash_nextentry(&help_files)) {
    if (strcmp(curr->file, filename) == 0) {
      if (curr->indx)
        mush_free(curr->indx, "help_index");
      curr->indx = NULL;
      curr->entries = 0;
      help_build_index(curr, curr->admin);
      retval = 1;
    }
  }
  return retval;
}
Beispiel #21
0
/** Rebuild a help file index.
 * \verbatim
 * This command implements @readcache.
 * \endverbatim
 * \param player the enactor.
 */
void
help_reindex(dbref player)
{
  help_file *curr;

  for (curr = hash_firstentry(&help_files);
       curr; curr = hash_nextentry(&help_files)) {
    if (curr->indx) {
      mush_free(curr->indx, "help_index");
      curr->indx = NULL;
      curr->entries = 0;
    }
    help_build_index(curr, curr->admin);
  }
  if (player != NOTHING) {
    notify(player, T("Help files reindexed."));
    do_rawlog(LT_WIZ, "Help files reindexed by %s(#%d)", Name(player), player);
  } else
    do_rawlog(LT_WIZ, "Help files reindexed.");
}
Beispiel #22
0
/** Restore the previously saved timezone. */
void
restore_tz(void)
{
  if (saved_tz) {
#ifdef WIN32
    _putenv_s("TZ", saved_tz);
#else
    setenv("TZ", saved_tz, 1);
#endif
    mush_free(saved_tz, "timezone");
    saved_tz = NULL;
  } else {
#ifdef WIN32
    _putenv_s("TZ", "");
#else
    unsetenv("TZ");
#endif
  }

  tzset();
}
Beispiel #23
0
/* ------------------------------------------------------------------------ */
void free_nebulainfo(void *ptr) {
  aspace_borders *nebula = (aspace_borders *) ptr;
  mush_free(nebula->name, "spacenebula_name");
  mush_free(nebula, "nebula_info");
}
Beispiel #24
0
/** The switch command.
 * \verbatim
 * For lack of better place the @switch code is here.
 * @switch expression=args
 * \endverbatim
 * \param executor the executor.
 * \param expression the expression to test against cases.
 * \param argv array of cases and actions.
 * \param enactor the object that caused this code to run.
 * \param first if 1, run only first matching case; if 0, run all matching cases.
 * \param notifyme if 1, perform a notify after executing matched cases.
 * \param regexp if 1, do regular expression matching; if 0, wildcard globbing.
 * \param queue_type the type of queue to run any new commands as
 * \param queue_entry the queue entry \@switch is being run in
 */
void
do_switch(dbref executor, char *expression, char **argv, dbref enactor,
          int first, int notifyme, int regexp, int queue_type,
          MQUE *queue_entry)
{
  int any = 0, a;
  char buff[BUFFER_LEN], *bp;
  char const *ap;
  char *tbuf1;
  PE_REGS *pe_regs;

  if (!argv[1])
    return;

  /* now try a wild card match of buff with stuff in coms */
  for (a = 1;
       !(first && any) && (a < (MAX_ARG - 1)) && argv[a] && argv[a + 1];
       a += 2) {
    /* eval expression */
    ap = argv[a];
    bp = buff;
    if (process_expression(buff, &bp, &ap, executor, enactor, enactor,
                           PE_DEFAULT, PT_DEFAULT, queue_entry->pe_info)) {
      return;
    }
    *bp = '\0';
    /* check for a match */
    pe_regs = pe_regs_create(PE_REGS_SWITCH | PE_REGS_CAPTURE, "do_switch");
    pe_regs_set(pe_regs, PE_REGS_SWITCH, "t0", expression);
    if (regexp ? regexp_match_case_r(buff, expression, 0,
                                     NULL, 0, NULL, 0, pe_regs, 0)
        : local_wild_match(buff, expression, pe_regs)) {
      tbuf1 = replace_string("#$", expression, argv[a + 1]);
      if (!any) {
        /* Add the new switch context to the parent queue... */
        any = 1;
      }
      if (queue_type & QUEUE_INPLACE) {
        new_queue_actionlist(executor, enactor, enactor, tbuf1, queue_entry,
                             PE_INFO_SHARE, queue_type, pe_regs);
      } else {
        new_queue_actionlist(executor, enactor, enactor, tbuf1, queue_entry,
                             PE_INFO_CLONE, queue_type, pe_regs);
      }
      mush_free(tbuf1, "replace_string.buff");
    }
  }
  /* do default if nothing has been matched */
  if ((a < MAX_ARG) && !any && argv[a]) {
    tbuf1 = replace_string("#$", expression, argv[a]);
    pe_regs = pe_regs_create(PE_REGS_SWITCH | PE_REGS_CAPTURE, "do_switch");
    pe_regs_set(pe_regs, PE_REGS_SWITCH, "t0", expression);
    if (queue_type & QUEUE_INPLACE) {
      new_queue_actionlist(executor, enactor, enactor, tbuf1, queue_entry,
                           PE_INFO_SHARE, queue_type, pe_regs);
    } else {
      new_queue_actionlist(executor, enactor, enactor, tbuf1, queue_entry,
                           PE_INFO_CLONE, queue_type, pe_regs);
    }
    mush_free(tbuf1, "replace_string.buff");
  }

  if (!(queue_type & QUEUE_INPLACE) && notifyme) {
    parse_que(executor, enactor, "@notify me", NULL);
  }
}
Beispiel #25
0
/** Tree delete.  Decrement the usage count of the string, unless the
 * count is pegged.  If count reaches zero, delete.
 * \param s string to find and delete.
 * \param root pointer to root of string tree.
 */
void
st_delete(char const *s, StrTree *root)
{
  int tree_depth;
  StrNode *y;
  StrNode *x;
  int cmp;

  assert(s);

  /* Hunt for the string in the tree. */
  tree_depth = 0;
  y = root->root;
  while (y && (cmp = strcmp(s, y->string))) {
    path[tree_depth] = y;
    tree_depth++;
    assert(tree_depth < ST_MAX_DEPTH);
    if (cmp < 0)
      y = y->left;
    else
      y = y->right;
  }

  /* If it wasn't in the tree, we're done. */
  if (!y)
    return;

  /* If this node is permanent, then we're done. */
  if (y->info >= ST_USE_LIMIT)
    return;

  /* If this node has been used more than once, then decrement and exit. */
  if (y->info >= ST_USE_STEP * 2) {
    y->info -= ST_USE_STEP;
    return;
  }
  if (y->left && y->right) {
    /* It has two children.  We need to swap with successor. */
    int z_depth;
    char color;
    /* Record where we are. */
    z_depth = tree_depth;
    /* Find the successor. */
    path[tree_depth] = y;
    tree_depth++;
    y = y->right;
    while (y->left) {
      path[tree_depth] = y;
      tree_depth++;
      y = y->left;
    }
    /* Fix the parent's pointer... */
    if (z_depth == 0)
      root->root = y;
    else if (path[z_depth - 1]->left == path[z_depth])
      path[z_depth - 1]->left = y;
    else
      path[z_depth - 1]->right = y;
    /* Swap out the path pieces. */
    path[tree_depth] = path[z_depth];
    path[z_depth] = y;
    y = path[tree_depth];
    /* Swap out the child pointers */
    path[z_depth]->left = y->left;
    y->left = NULL;
    y->right = path[z_depth]->right;
    path[z_depth]->right = path[z_depth + 1];
    /* Fix the child pointer of the parent of the replacement */
    if (tree_depth > z_depth + 1)
      path[tree_depth - 1]->left = y;
    else
      path[tree_depth - 1]->right = y;
    /* Swap out the color */
    color = y->info & ST_COLOR;
    y->info = (y->info & ~ST_COLOR) | (path[z_depth]->info & ST_COLOR);
    path[z_depth]->info = (path[z_depth]->info & ~ST_COLOR) | color;
  }

  /* We are now looking at a node with less than two children */
  assert(!y->left || !y->right);
  /* Move the child (if any) up */
  if (y->left)
    x = y->left;
  else
    x = y->right;
  if (root->root == y)
    root->root = x;
  else if (path[tree_depth - 1]->left == y)
    path[tree_depth - 1]->left = x;
  else
    path[tree_depth - 1]->right = x;
  if ((y->info & ST_COLOR) == ST_BLACK) {
    while (x != root->root && (!x || (x->info & ST_COLOR) == ST_BLACK)) {
      if (x == path[tree_depth - 1]->left) {
        StrNode *w = path[tree_depth - 1]->right;
        assert(w);
        if (w && (w->info & ST_COLOR) == ST_RED) {
          w->info &= ~ST_RED;
          path[tree_depth - 1]->info |= ST_RED;
          st_left_rotate(tree_depth - 1, &root->root);
          path[tree_depth] = path[tree_depth - 1];
          path[tree_depth - 1] = w;
          tree_depth++;
          w = path[tree_depth - 1]->right;
          assert(w);
        }
        assert((w->info & ST_COLOR) == ST_BLACK);
        if ((!w->left || (w->left->info & ST_COLOR) == ST_BLACK) &&
            (!w->right || (w->right->info & ST_COLOR) == ST_BLACK)) {
          w->info |= ST_RED;
          x = path[tree_depth - 1];
          tree_depth--;
        } else {
          if (!w->right || (w->right->info & ST_COLOR) == ST_BLACK) {
            assert(w->left);
            w->left->info &= ~ST_RED;
            path[tree_depth] = w;
            st_right_rotate(tree_depth, &root->root);
            w = path[tree_depth - 1]->right;
            assert(w);
          }
          w->info =
            (w->info & ~ST_COLOR) | (path[tree_depth - 1]->info & ST_COLOR);
          path[tree_depth - 1]->info &= ~ST_RED;
          assert(w->right);
          w->right->info &= ~ST_RED;
          st_left_rotate(tree_depth - 1, &root->root);
          x = root->root;
        }
      } else {
        StrNode *w = path[tree_depth - 1]->left;
        assert(w);
        if (w && (w->info & ST_COLOR) == ST_RED) {
          w->info &= ~ST_RED;
          path[tree_depth - 1]->info |= ST_RED;
          st_right_rotate(tree_depth - 1, &root->root);
          path[tree_depth] = path[tree_depth - 1];
          path[tree_depth - 1] = w;
          tree_depth++;
          w = path[tree_depth - 1]->left;
          assert(w);
        }
        assert((w->info & ST_COLOR) == ST_BLACK);
        if ((!w->right || (w->right->info & ST_COLOR) == ST_BLACK) &&
            (!w->left || (w->left->info & ST_COLOR) == ST_BLACK)) {
          w->info |= ST_RED;
          x = path[tree_depth - 1];
          tree_depth--;
        } else {
          if (!w->left || (w->left->info & ST_COLOR) == ST_BLACK) {
            assert(w->right);
            w->right->info &= ~ST_RED;
            path[tree_depth] = w;
            st_left_rotate(tree_depth, &root->root);
            w = path[tree_depth - 1]->left;
            assert(w);
          }
          w->info =
            (w->info & ~ST_COLOR) | (path[tree_depth - 1]->info & ST_COLOR);
          path[tree_depth - 1]->info &= ~ST_RED;
          assert(w->left);
          w->left->info &= ~ST_RED;
          st_right_rotate(tree_depth - 1, &root->root);
          x = root->root;
        }
      }
    }
    if (x)
      x->info &= ~ST_RED;
  }
  root->mem -= strlen(s) + 1;
  mush_free(y, "StrNode");
  root->count--;
}
Beispiel #26
0
/** Rename something.
 * \verbatim
 * This implements @name.
 * \endverbatim
 * \param player the enactor.
 * \param name current name of object to rename.
 * \param newname_ new name for object.
 */
void
do_name(dbref player, const char *name, char *newname_)
{
  dbref thing;
  char oldname[BUFFER_LEN];
  char *newname = NULL;
  char *alias = NULL;
  PE_REGS *pe_regs;

  if ((thing = match_controlled(player, name)) == NOTHING)
    return;

  /* check for bad name */
  if ((*newname_ == '\0') || strchr(newname_, '[')) {
    notify(player, T("Give it what new name?"));
    return;
  }
  switch (Typeof(thing)) {
  case TYPE_PLAYER:
    switch (ok_object_name
            (newname_, player, thing, TYPE_PLAYER, &newname, &alias)) {
    case OPAE_INVALID:
    case OPAE_NULL:
      notify(player, T("You can't give a player that name or alias."));
      if (newname)
        mush_free(newname, "name.newname");
      if (alias)
        mush_free(alias, "name.newname");
      return;
    case OPAE_TOOMANY:
      notify(player, T("Too many aliases."));
      mush_free(newname, "name.newname");
      return;
    case OPAE_SUCCESS:
      break;
    }
    break;
  case TYPE_EXIT:
    if (ok_object_name(newname_, player, thing, TYPE_EXIT, &newname, &alias) !=
        OPAE_SUCCESS) {
      notify(player, T("That is not a reasonable name."));
      if (newname)
        mush_free(newname, "name.newname");
      if (alias)
        mush_free(alias, "name.newname");
      return;
    }
    break;
  case TYPE_THING:
  case TYPE_ROOM:
    if (!ok_name(newname_, 0)) {
      notify(player, T("That is not a reasonable name."));
      return;
    }
    newname = mush_strdup(trim_space_sep(newname_, ' '), "name.newname");
    break;
  default:
    /* Should never occur */
    notify(player, T("I don't see that here."));
    return;
  }

  /* Actually change it */
  mush_strncpy(oldname, Name(thing), BUFFER_LEN);

  if (IsPlayer(thing)) {
    do_log(LT_CONN, 0, 0, "Name change by %s(#%d) to %s",
           Name(thing), thing, newname);
    if (Suspect(thing) && strcmp(Name(thing), newname) != 0)
      flag_broadcast("WIZARD", 0,
                     T("Broadcast: Suspect %s changed name to %s."),
                     Name(thing), newname);
    reset_player_list(thing, Name(thing), NULL, newname, NULL);
  }
  set_name(thing, newname);
  if (alias) {
    if (*alias == ALIAS_DELIMITER) {
      do_set_atr(thing, "ALIAS", NULL, player, 0);
    } else {
      /* New alias to set */
      do_set_atr(thing, "ALIAS", alias, player, 0);
    }
    mush_free(alias, "name.newname");
  }

  queue_event(player, "OBJECT`RENAME", "%s,%s,%s",
              unparse_objid(thing), newname, oldname);

  if (!AreQuiet(player, thing))
    notify(player, T("Name set."));
  pe_regs = pe_regs_create(PE_REGS_ARG, "do_name");
  pe_regs_setenv_nocopy(pe_regs, 0, oldname);
  pe_regs_setenv_nocopy(pe_regs, 1, newname);
  real_did_it(player, thing, NULL, NULL, "ONAME", NULL, "ANAME", NOTHING,
              pe_regs, NA_INTER_PRESENCE, AN_SYS);
  pe_regs_free(pe_regs);
  mush_free(newname, "name.newname");
}
Beispiel #27
0
/** Migrate some number of chunks.
 * The requested amount is only a guideline; the actual amount
 * migrated will be more or less due to always migrating all the
 * attributes, locks, and mail on any given object together.
 * \param amount the suggested number of attributes to migrate.
 */
static void
migrate_stuff(int amount)
{
  static int start_obj = 0;
  static chunk_reference_t **refs = NULL;
  static int refs_size = 0;
  int end_obj;
  int actual;
  ATTR *aptr;
  lock_list *lptr;
  MAIL *mp;

  if (db_top == 0)
    return;

  end_obj = start_obj;
  actual = 0;
  do {
    for (aptr = List(end_obj); aptr; aptr = AL_NEXT(aptr))
      if (aptr->data != NULL_CHUNK_REFERENCE)
        actual++;
    for (lptr = Locks(end_obj); lptr; lptr = L_NEXT(lptr))
      if (L_KEY(lptr) != NULL_CHUNK_REFERENCE)
        actual++;
    if (IsPlayer(end_obj)) {
      for (mp = find_exact_starting_point(end_obj); mp; mp = mp->next)
        if (mp->msgid != NULL_CHUNK_REFERENCE)
          actual++;
    }
    end_obj = (end_obj + 1) % db_top;
  } while (actual < amount && end_obj != start_obj);

  if (actual == 0)
    return;

  if (!refs || actual > refs_size) {
    if (refs)
      mush_free(refs, "migration reference array");
    refs =
      mush_calloc(actual, sizeof(chunk_reference_t *),
                  "migration reference array");
    refs_size = actual;
    if (!refs)
      mush_panic("Could not allocate migration reference array");
  }
#ifdef DEBUG_MIGRATE
  do_rawlog(LT_TRACE, "Migrate asked %d, actual objects #%d to #%d for %d",
            amount, start_obj, (end_obj + db_top - 1) % db_top, actual);
#endif

  actual = 0;
  do {
    for (aptr = List(start_obj); aptr; aptr = AL_NEXT(aptr))
      if (aptr->data != NULL_CHUNK_REFERENCE) {
        refs[actual] = &(aptr->data);
        actual++;
      }
    for (lptr = Locks(start_obj); lptr; lptr = L_NEXT(lptr))
      if (L_KEY(lptr) != NULL_CHUNK_REFERENCE) {
        refs[actual] = &(lptr->key);
        actual++;
      }
    if (IsPlayer(start_obj)) {
      for (mp = find_exact_starting_point(start_obj); mp; mp = mp->next)
        if (mp->msgid != NULL_CHUNK_REFERENCE) {
          refs[actual] = &(mp->msgid);
          actual++;
        }
    }
    start_obj = (start_obj + 1) % db_top;
  } while (start_obj != end_obj);

  chunk_migration(actual, refs);
}
Beispiel #28
0
static struct tzinfo *
do_read_tzfile(int fd, const char *tzfile, int time_size)
{
  struct tzinfo *tz = NULL;
  int size, n;
  bool has_64bit_times = 0;
  int isstdcnt, isgmtcnt;

  {
    char magic[5] = { '\0' };

    if (read(fd, magic, 4) != 4) {
      do_rawlog(LT_ERR, "tz: Unable to read header from %s: %s.\n", tzfile,
                strerror(errno));
      goto error;
    }

    if (memcmp(magic, TZMAGIC, 4) != 0) {
      do_rawlog(LT_ERR, "tz: %s is not a valid tzfile. Wrong magic number.\n",
                tzfile);
      goto error;
    }
  }

  {
    char version[16];
    if (read(fd, version, 16) != 16) {
      do_rawlog(LT_ERR, "tz: Unable to read chunk from %s: %s\n", tzfile,
                strerror(errno));
      goto error;
    }

    /* There's a second copy of the data using 64 bit times, following
       the chunk with 32 bit times. */
    if (version[0] == '2')
      has_64bit_times = 1;
  }

  tz = mush_malloc(sizeof *tz, "timezone");
  memset(tz, 0, sizeof *tz);

  {
    int32_t counts[6];

    READ_CHUNK(counts, sizeof counts);

    isgmtcnt = decode32(counts[0]);
    isstdcnt = decode32(counts[1]);
    tz->leapcnt = decode32(counts[2]);
    tz->timecnt = decode32(counts[3]);
    tz->typecnt = decode32(counts[4]);
    tz->charcnt = decode32(counts[5]);
  }

  /* Use 64-bit time_t version on such systems. */
  if (has_64bit_times && sizeof(time_t) == 8 && time_size == 4) {
    off_t skip = 44;            /* Header and sizes */

    skip += tz->timecnt * 5;
    skip += tz->typecnt * 6;
    skip += tz->charcnt;
    skip += tz->leapcnt * (4 + time_size);
    skip += isgmtcnt + isstdcnt;

    if (lseek(fd, skip, SEEK_SET) < 0) {
      do_rawlog(LT_ERR, "tz: Unable to seek to second section of %s: %s\n",
                tzfile, strerror(errno));
      goto error;
    }

    mush_free(tz, "timezone");
    return do_read_tzfile(fd, tzfile, 8);
  }
#define READ_TRANSITIONS(type, decode)			\
  do {							\
    type *buf;						\
    							\
    size = tz->timecnt * time_size;			\
    buf = malloc(size);						\
    READ_CHUNKF(buf, size);					\
    								\
    tz->transitions = calloc(tz->timecnt, sizeof(time_t));	\
    for (n = 0; n < tz->timecnt; n += 1)			\
      tz->transitions[n] = (time_t) decode(buf[n]);		\
    								\
    free(buf);							\
  } while (0)

  if (time_size == 4) {
    READ_TRANSITIONS(int32_t, decode32);
  } else {
    READ_TRANSITIONS(int64_t, decode64);
  }

  tz->offset_indexes = malloc(tz->timecnt);
  READ_CHUNK(tz->offset_indexes, tz->timecnt);

  {
    uint8_t *buf;
    int m, size = tz->typecnt * 6;

    buf = malloc(size);
    READ_CHUNKF(buf, size);

    tz->offsets = calloc(tz->typecnt, sizeof(struct ttinfo));

    for (n = 0, m = 0; n < tz->typecnt; n += 1, m += 6) {
      int32_t gmtoff;

      memcpy(&gmtoff, &buf[m], 4);
      tz->offsets[n].tt_gmtoff = decode32(gmtoff);
      tz->offsets[n].tt_isdst = buf[m + 4];
      tz->offsets[n].tt_abbrind = buf[m + 5];
      tz->offsets[n].tt_std = tz->offsets[n].tt_utc = 0;
    }

    free(buf);
  }

  tz->abbrevs = malloc(tz->charcnt);
  READ_CHUNK(tz->abbrevs, tz->charcnt);

#define READ_LEAPSECS(type, decode) \
  do {				    \
    type *buf;					 \
    int m, size = tz->leapcnt * (4 + time_size); \
    						 \
    buf = malloc(size);				 \
    READ_CHUNKF(buf, size);			 \
    									\
    tz->leapsecs = calloc(tz->leapcnt, sizeof(struct ttleapsecs));	\
    									\
    for (n = 0, m = 0; n < tz->leapcnt; n += 1, m += (4 + time_size)) { \
       type when;							\
      int32_t secs;							\
      									\
      memcpy(&when, buf, time_size);					\
      memcpy(&secs, buf + time_size, 4);				\
      tz->leapsecs[n].tt_when = (time_t) decode(when);			\
      tz->leapsecs[n].tt_secs = decode32(secs);				\
    }									\
    free(buf);								\
  } while (0)

  if (tz->leapcnt) {
    if (time_size == 4)
      READ_LEAPSECS(int32_t, decode32);
    else
      READ_LEAPSECS(int64_t, decode64);
  }

  {
    uint8_t *buf;
    int n;

    buf = malloc(isstdcnt);
    READ_CHUNKF(buf, isstdcnt);

    for (n = 0; n < isstdcnt; n += 1)
      tz->offsets[n].tt_std = buf[n];

    free(buf);

    buf = malloc(isgmtcnt);
    READ_CHUNKF(buf, isgmtcnt);

    for (n = 0; n < isgmtcnt; n += 1)
      tz->offsets[n].tt_utc = buf[n];

    free(buf);
  }

  return tz;

error:
  if (tz)
    free_tzinfo(tz);
  return NULL;
}
Beispiel #29
0
static void
free_entry_list(char **entries)
{
  if (entries)
    mush_free(entries, "help.search");
}
Beispiel #30
0
/** Create an exit.
 * This function opens an exit and optionally links it.
 * \param player the enactor.
 * \param direction the name of the exit.
 * \param linkto the room to link to, as a string.
 * \param pseudo a phony location for player if a back exit is needed. This is bpass by do_open() as the source room of the back exit.
 * \return dbref of the new exit, or NOTHING.
 */
dbref
do_real_open(dbref player, const char *direction, const char *linkto,
             dbref pseudo)
{
  dbref loc =
    (pseudo !=
     NOTHING) ? pseudo : (IsExit(player) ? Source(player) : (IsRoom(player) ?
                                                             player :
                                                             Location(player)));
  dbref new_exit;
  char *flaglist, *flagname;
  char flagbuff[BUFFER_LEN];
  char *name = NULL;
  char *alias = NULL;

  if (!command_check_byname(player, "@dig")) {
    notify(player, T("Permission denied."));
    return NOTHING;
  }
  if ((loc == NOTHING) || (!IsRoom(loc))) {
    notify(player, T("Sorry, you can only make exits out of rooms."));
    return NOTHING;
  }
  if (Going(loc)) {
    notify(player, T("You can't make an exit in a place that's crumbling."));
    return NOTHING;
  }
  if (!*direction) {
    notify(player, T("Open where?"));
    return NOTHING;
  } else
    if (ok_object_name
        ((char *) direction, player, NOTHING, TYPE_EXIT, &name, &alias) < 1) {
    notify(player, T("That's a strange name for an exit!"));
    if (name)
      mush_free(name, "name.newname");
    if (alias)
      mush_free(alias, "name.newname");
    return NOTHING;
  }
  if (!Open_Anywhere(player) && !controls(player, loc)) {
    notify(player, T("Permission denied."));
  } else if (can_pay_fees(player, EXIT_COST)) {
    /* create the exit */
    new_exit = new_object();

    /* initialize everything */
    set_name(new_exit, name);
    if (alias && *alias != ALIAS_DELIMITER)
      atr_add(new_exit, "ALIAS", alias, player, 0);
    Owner(new_exit) = Owner(player);
    Zone(new_exit) = Zone(player);
    Source(new_exit) = loc;
    Type(new_exit) = TYPE_EXIT;
    Flags(new_exit) = new_flag_bitmask("FLAG");
    strcpy(flagbuff, options.exit_flags);
    flaglist = trim_space_sep(flagbuff, ' ');
    if (*flaglist != '\0') {
      while (flaglist) {
        flagname = split_token(&flaglist, ' ');
        twiddle_flag_internal("FLAG", new_exit, flagname, 0);
      }
    }

    mush_free(name, "name.newname");
    if (alias)
      mush_free(alias, "name.newname");

    /* link it in */
    PUSH(new_exit, Exits(loc));

    /* and we're done */
    notify_format(player, T("Opened exit %s"), unparse_dbref(new_exit));

    /* check second arg to see if we should do a link */
    if (linkto && *linkto != '\0') {
      notify(player, T("Trying to link..."));
      if ((loc = check_var_link(linkto)) == NOTHING)
        loc = parse_linkable_room(player, linkto);
      if (loc != NOTHING) {
        if (!payfor(player, LINK_COST)) {
          notify_format(player, T("You don't have enough %s to link."), MONIES);
        } else {
          /* it's ok, link it */
          Location(new_exit) = loc;
          notify_format(player, T("Linked exit #%d to #%d"), new_exit, loc);
        }
      }
    }
    current_state.exits++;
    local_data_create(new_exit);
    queue_event(player, "OBJECT`CREATE", "%s", unparse_objid(new_exit));
    return new_exit;
  }
  if (name)
    mush_free(name, "name.newname");
  if (alias)
    mush_free(alias, "name.newname");

  return NOTHING;
}