/** 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); }
/* 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; }
/** * 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"); }
/** 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"); }
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"); }
/** * 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"); }
/** 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; }
/** 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; }
/** 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); }
/** 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"); }
/** 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; }
/** * 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; }
/** 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"); } }
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; }
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); }
static void delete_node(StrNode *node) { if (node->left) delete_node(node->left); if (node->right) delete_node(node->right); mush_free(node, "StrNode"); }
/** 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"); }
/** 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; }
/** 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); }
/** 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; }
/** 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."); }
/** 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(); }
/* ------------------------------------------------------------------------ */ void free_nebulainfo(void *ptr) { aspace_borders *nebula = (aspace_borders *) ptr; mush_free(nebula->name, "spacenebula_name"); mush_free(nebula, "nebula_info"); }
/** 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); } }
/** 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--; }
/** 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"); }
/** 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); }
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; }
static void free_entry_list(char **entries) { if (entries) mush_free(entries, "help.search"); }
/** 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; }