/* 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; }
/** Allocate memory for a buffer queue to hold a given number of lines. * \param bq pointer to buffer queue. * \param lines lines to allocate for buffer queue. * \retval address of allocated buffer queue. */ BUFFERQ * allocate_bufferq(int lines) { BUFFERQ *bq; int bytes = lines * (BUFFER_LEN + BUFFERQLINEOVERHEAD); bq = mush_malloc(sizeof(BUFFERQ), "bufferq"); bq->buffer = mush_malloc(bytes, "bufferq.buffer"); *bq->buffer = '\0'; bq->buffer_end = bq->buffer; bq->num_buffered = 0; bq->buffer_size = bytes; strcpy(bq->last_string, ""); bq->last_type = 0; return bq; }
static struct access *sitelock_alloc(const char *host, dbref who, uint32_t can, uint32_t cant, const char *comment, const char **errptr) { struct access *tmp; tmp = mush_malloc(sizeof(struct access), "sitelock.rule"); if (!tmp) { static const char *memerr = "unable to allocate memory"; if (errptr) *errptr = memerr; return NULL; } tmp->who = who; tmp->can = can; tmp->cant = cant; tmp->host = mush_strdup(host, "sitelock.rule.pattern"); if (comment && *comment) tmp->comment = mush_strdup(comment, "sitelock.rule.comment"); else tmp->comment = NULL; tmp->next = NULL; if (can & ACS_REGEXP) { int erroffset = 0; tmp->re = pcre_compile(host, 0, errptr, &erroffset, tables); if (!tmp->re) { sitelock_free(tmp); return NULL; } } else tmp->re = NULL; return tmp; }
/** 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); }
/* Add a new, or restrict an existing, standard attribute from cnf file */ int cnf_attribute_access(char *attrname, char *opts) { ATTR *a; privbits flags = 0; upcasestr(attrname); if (!good_atr_name(attrname)) return 0; if (strcasecmp(opts, "none")) { flags = list_to_privs(attr_privs_set, opts, 0); if (!flags) return 0; } a = (ATTR *) ptab_find_exact(&ptab_attrib, attrname); if (a) { if (AF_Internal(a)) return 0; } else { a = (ATTR *) mush_malloc(sizeof(ATTR), "ATTR"); if (!a) return 0; AL_NAME(a) = strdup(attrname); a->data = NULL_CHUNK_REFERENCE; ptab_insert_one(&ptab_attrib, attrname, a); } AL_FLAGS(a) = flags; AL_CREATOR(a) = GOD; return 1; }
void addNewNebula(dbref executor, int index, const char* name, double radius, double x, double y, double z, char *buff, char **bp) { aspace_borders* newNebula; newNebula = im_find(nebula_map, index); if (newNebula != NULL) { safe_str("#-1 NEBULA # ALREADY IN USE", buff, bp); return; } newNebula = mush_malloc(sizeof(aspace_borders), "nebula_info"); newNebula->name = mush_strdup(name, "spacenebula_name"); newNebula->empire_id = 0; newNebula->radius = radius; newNebula->x = x; newNebula->y = y; newNebula->z = z; if( im_insert(nebula_map, index, newNebula )) { safe_str("New nebula Created.", buff, bp); write_spacelog(executor, executor, tprintf("Nebula Created: %s", newNebula->name)); } else safe_str("#-1 NEBULA NOT CREATED.", buff, bp); }
/** Allocate and initialize a new integer map. */ intmap * im_new(void) { intmap *im; im = mush_malloc(sizeof *im, "int_map"); if (!intmap_slab) intmap_slab = slab_create("patricia tree nodes", sizeof(struct patricia)); im->count = 0; im->root = NULL; return im; }
/** Add a new lock to the table. * \param name The name of the lock * \param flags The default flags. */ void define_lock(lock_type name, privbits flags) { lock_list *newlock; newlock = mush_malloc(sizeof *newlock, "lock"); newlock->type = mush_strdup(strupper(name), "lock.name"); newlock->flags = flags; newlock->creator = GOD; newlock->key = TRUE_BOOLEXP; newlock->next = NULL; hashadd((char *) newlock->type, newlock, &htab_locks); }
/* Ads a module entry and returns */ struct module_entry_t *module_entry_add(char *name) { struct module_entry_t *entry; entry = (struct module_entry_t *) mush_malloc(sizeof(struct module_entry_t), "MODULE_ENTRY"); if(!entry) { return NULL; /* Should really panic here.. */ } entry->name = mush_strdup(name, "MODULE_ENTRY.NAME"); entry->info = NULL; entry->load = NULL; entry->unload = NULL; entry->next = module_list; module_list = entry; return entry; }
/** Add a new attribute. Called from db.c to add new attributes * to older databases which have their own attr table. * \param name name of attr to add * \param flags attribute flags (AF_*) */ void add_new_attr(char *name, uint32_t flags) { ATTR *ap; ap = (ATTR *) ptab_find_exact(&ptab_attrib, name); if (ap || !good_atr_name(name)) return; ap = (ATTR *) mush_malloc(sizeof(ATTR), "ATTR"); if (!ap) { do_log(LT_ERR, 0, 0, "add_new_attr: unable to malloc ATTR"); return; } AL_NAME(ap) = strdup(name); ap->data = NULL_CHUNK_REFERENCE; AL_FLAGS(ap) = flags; AL_CREATOR(ap) = 0; ptab_insert_one(&ptab_attrib, name, ap); }
/** 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); }
static lock_list * next_free_lock(void) { lock_list *ll; if (!free_list) { size_t n; ll = mush_malloc(sizeof(lock_list) * LOCKS_PER_PAGE, "lock_page"); if (!ll) mush_panic("Unable to allocate memory for locks!"); for (n = 0; n < LOCKS_PER_PAGE - 1; n++) { ll[n].type = NULL; ll[n].key = TRUE_BOOLEXP; ll[n].creator = NOTHING; ll[n].flags = 0; ll[n].next = &ll[n + 1]; } ll[n].next = NULL; ll[n].type = NULL; ll[n].key = TRUE_BOOLEXP; ll[n].creator = NOTHING; ll[n].flags = 0; free_list = &ll[0]; } ll = free_list; free_list = ll->next; ll->type = NULL; ll->key = TRUE_BOOLEXP; return ll; }
void addNewBorder(dbref executor, int border_number, const char* name, double radius, double x, double y, double z, char *buff, char **bp) { aspace_borders* newBorder; newBorder = im_find(border_map, border_number); if (newBorder != NULL) { safe_str("#-1 BORDER ALREADY EXISTS", buff, bp); return; } newBorder = mush_malloc(sizeof(aspace_borders), "border_info"); newBorder->name = mush_strdup(name, "spaceborder_name"); newBorder->empire_id = 0; newBorder->radius = radius; newBorder->x = x; newBorder->y = y; newBorder->z = z; if( im_insert(border_map, border_number, newBorder )) { safe_str("New Border Created.", buff, bp); write_spacelog(executor, executor, tprintf("Border Created: %s", newBorder->name)); } else safe_str("#-1 BORDER NOT CREATED.", buff, bp); }
/** Add new standard attributes, or change permissions on them. * \verbatim * Given the name and permission string for an attribute, add it to * the attribute table (or modify the permissions if it's already * there). Permissions may be changed retroactively, which modifies * permissions on any copies of that attribute set on objects in the * database. This is the top-level code for @attribute/access. * \endverbatim * \param player the enactor. * \param name the attribute name. * \param perms a string of attribute permissions, space-separated. * \param retroactive if true, apply the permissions retroactively. */ void do_attribute_access(dbref player, char *name, char *perms, int retroactive) { ATTR *ap, *ap2; privbits flags = 0; int i; int insert = 0; /* Parse name and perms */ if (!name || !*name) { notify(player, T("Which attribute do you mean?")); return; } if (strcasecmp(perms, "none")) { flags = list_to_privs(attr_privs_set, perms, 0); if (!flags) { notify(player, T("I don't understand those permissions.")); return; } } upcasestr(name); /* Is this attribute already in the table? */ ap = (ATTR *) ptab_find_exact(&ptab_attrib, name); if (ap) { if (AF_Internal(ap)) { /* Don't muck with internal attributes */ notify(player, T("That attribute's permissions can not be changed.")); return; } } else { /* Create fresh if the name is ok */ if (!good_atr_name(name)) { notify(player, T("Invalid attribute name.")); return; } insert = 1; ap = (ATTR *) mush_malloc(sizeof(ATTR), "ATTR"); if (!ap) { notify(player, T("Critical memory failure - Alert God!")); do_log(LT_ERR, 0, 0, "do_attribute_access: unable to malloc ATTR"); return; } AL_NAME(ap) = strdup(name); ap->data = NULL_CHUNK_REFERENCE; } AL_FLAGS(ap) = flags; AL_CREATOR(ap) = player; /* Only insert when it's not already in the table */ if (insert) { ptab_insert_one(&ptab_attrib, name, ap); } /* Ok, now we need to see if there are any attributes of this name * set on objects in the db. If so, and if we're retroactive, set * perms/creator */ if (retroactive) { for (i = 0; i < db_top; i++) { if ((ap2 = atr_get_noparent(i, name))) { if (AL_FLAGS(ap2) & AF_ROOT) AL_FLAGS(ap2) = flags | AF_ROOT; else AL_FLAGS(ap2) = flags; AL_CREATOR(ap2) = player; } } } notify_format(player, T("%s -- Attribute permissions now: %s"), name, privs_to_string(attr_privs_view, flags)); }
/** String tree insert. If the string is already in the tree, bump its usage * count and return the tree's version. Otherwise, allocate a new tree * node, copy the string into the node, insert it into the tree, and * return the new node's string. * \param s string to insert in tree. * \param root pointer to root of string tree. * \return string inserted or NULL. */ char const * st_insert(char const *s, StrTree *root) { int tree_depth; StrNode *n; int cmp = 0; size_t keylen; assert(s); /* Hunt for the string in the tree. */ tree_depth = 0; n = root->root; while (n && (cmp = strcmp(s, n->string))) { path[tree_depth] = n; tree_depth++; assert(tree_depth < ST_MAX_DEPTH); if (cmp < 0) n = n->left; else n = n->right; } if (n) { /* Found the string, so bump the usage and return. */ if (n->info < ST_USE_LIMIT) n->info += ST_USE_STEP; return n->string; } /* Need a new node. Allocate and initialize it. */ keylen = strlen(s) + 1; n = mush_malloc(sizeof(StrNode) - BUFFER_LEN + keylen, "StrNode"); if (!n) return NULL; memcpy(n->string, s, keylen); n->left = NULL; n->right = NULL; if (tree_depth == 0) { /* This is the first insertion! Just stick it at the root * and get out of here. */ root->root = n; n->info = ST_BLACK + ST_USE_STEP; return n->string; } n->info = ST_RED + ST_USE_STEP; /* Foo. Have to do a complex insert. Well, start by putting * the new node at the tip of an appropriate branch. */ path[tree_depth] = n; tree_depth--; if (cmp < 0) path[tree_depth]->left = n; else path[tree_depth]->right = n; /* I rely on ST_RED != 0 and ST_BLACK == 0 in my bitwise ops. */ assert(ST_RED); /* Sigh. Fix the tree to maintain the red-black properties. */ while (tree_depth > 0 && (path[tree_depth]->info & ST_COLOR) == ST_RED) { /* We have a double-red. Blitch. Now we have some mirrored * cases to look for, so stuff is duplicated left/right. */ if (path[tree_depth] == path[tree_depth - 1]->left) { StrNode *y; y = path[tree_depth - 1]->right; if (y && (y->info & ST_COLOR) == ST_RED) { /* Hmph. Uncle is red. Push the mess up the tree. */ path[tree_depth]->info &= ~ST_RED; y->info &= ~ST_RED; tree_depth--; path[tree_depth]->info |= ST_RED; tree_depth--; } else { /* Okay, uncle is black. We can fix everything, now. */ if (path[tree_depth + 1] == path[tree_depth]->right) { st_left_rotate(tree_depth, &root->root); path[tree_depth + 1]->info &= ~ST_RED; } else { path[tree_depth]->info &= ~ST_RED; } path[tree_depth - 1]->info |= ST_RED; st_right_rotate(tree_depth - 1, &root->root); break; } } else { StrNode *y; y = path[tree_depth - 1]->left; if (y && (y->info & ST_COLOR) == ST_RED) { /* Hmph. Uncle is red. Push the mess up the tree. */ path[tree_depth]->info &= ~ST_RED; y->info &= ~ST_RED; tree_depth--; path[tree_depth]->info |= ST_RED; tree_depth--; } else { /* Okay, uncle is black. We can fix everything, now. */ if (path[tree_depth + 1] == path[tree_depth]->left) { st_right_rotate(tree_depth, &root->root); path[tree_depth + 1]->info &= ~ST_RED; } else { path[tree_depth]->info &= ~ST_RED; } path[tree_depth - 1]->info |= ST_RED; st_left_rotate(tree_depth - 1, &root->root); break; } } } /* The tree is now red-black true again. Make the root black * just for convenience. */ root->root->info &= ~ST_RED; root->count++; root->mem += strlen(s) + 1; return n->string; }
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 ATTR * attr_read(PENNFILE *f) { ATTR *a; char *tmp; dbref d = GOD; privbits flags = 0; a = (ATTR *) mush_malloc(sizeof(ATTR), "ATTR"); if (!a) { mush_panic("Not enough memory to add attribute in attr_read()!"); return NULL; } AL_NAME(a) = NULL; a->data = NULL_CHUNK_REFERENCE; AL_FLAGS(a) = 0; AL_CREATOR(a) = GOD; a->next = NULL; db_read_this_labeled_string(f, "name", &tmp); if (!good_atr_name(tmp)) { do_rawlog(LT_ERR, "Invalid attribute name '%s' in db.", tmp); (void) getstring_noalloc(f); /* flags */ (void) getstring_noalloc(f); /* creator */ (void) getstring_noalloc(f); /* data */ free_standard_attr(a, 0); return NULL; } AL_NAME(a) = strdup(tmp); db_read_this_labeled_string(f, "flags", &tmp); if (tmp && *tmp && strcasecmp(tmp, "none")) { flags = list_to_privs(attr_privs_db, tmp, 0); if (!flags) { do_rawlog(LT_ERR, "Invalid attribute flags for '%s' in db.", AL_NAME(a)); free((char *) AL_NAME(a)); (void) getstring_noalloc(f); /* creator */ (void) getstring_noalloc(f); /* data */ free_standard_attr(a, 0); return NULL; } } AL_FLAGS(a) = flags; db_read_this_labeled_dbref(f, "creator", &d); AL_CREATOR(a) = d; db_read_this_labeled_string(f, "data", &tmp); if (!tmp || !*tmp || !(AL_FLAGS(a) & (AF_ENUM | AF_RLIMIT))) { a->data = NULL_CHUNK_REFERENCE; } else if (AL_FLAGS(a) & AF_ENUM) { /* Store string as it is */ char *t = compress(tmp); a->data = chunk_create(t, strlen(t), 0); free(t); } else if (AL_FLAGS(a) & AF_RLIMIT) { /* Need to validate regexp */ char *t; pcre *re; const char *errptr; int erroffset; re = pcre_compile(tmp, PCRE_CASELESS, &errptr, &erroffset, tables); if (!re) { do_rawlog(LT_ERR, "Invalid regexp in limit for attribute '%s' in db.", AL_NAME(a)); free_standard_attr(a, 0); return NULL; } pcre_free(re); /* don't need it, just needed to check it */ t = compress(tmp); a->data = chunk_create(t, strlen(t), 0); free(t); } return a; }
/** 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++; #ifdef USE_MAILER if (IsPlayer(end_obj)) { for (mp = find_exact_starting_point(end_obj); mp; mp = mp->next) if (mp->msgid != NULL_CHUNK_REFERENCE) actual++; } #endif 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((Malloc_t) refs, "migration reference array"); refs = (chunk_reference_t **) mush_malloc(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++; } #ifdef USE_MAILER 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++; } } #endif start_obj = (start_obj + 1) % db_top; } while (start_obj != end_obj); chunk_migration(actual, refs); }
/** The whisper command. * \param player the enactor. * \param arg1 name of the object to whisper to. * \param arg2 message to whisper. * \param noisy if 1, others overhear that a whisper has occurred. * \param pe_info the pe_info for evaluating interact locks */ void do_whisper(dbref player, const char *arg1, const char *arg2, int noisy, NEW_PE_INFO *pe_info) { dbref who; int key; const char *gap; char *tbuf, *tp; char *p; dbref good[100]; int gcount = 0; const char *head; int overheard; char *current; const char **start; char sname[BUFFER_LEN]; if (!arg1 || !*arg1) { notify(player, T("Whisper to whom?")); return; } if (!arg2 || !*arg2) { notify(player, T("Whisper what?")); return; } tp = tbuf = (char *) mush_malloc(BUFFER_LEN, "string"); if (!tbuf) mush_panic("Unable to allocate memory in do_whisper"); overheard = 0; head = arg1; start = &head; /* Figure out what kind of message */ gap = " "; switch (*arg2) { case SEMI_POSE_TOKEN: gap = ""; case POSE_TOKEN: key = 1; arg2++; break; default: key = 2; break; } *tp = '\0'; /* Make up a list of good and bad names */ while (head && *head) { current = next_in_list(start); who = match_result(player, current, TYPE_PLAYER, MAT_NEAR_THINGS | MAT_CONTAINER); if (!GoodObject(who) || !can_interact(player, who, INTERACT_HEAR, pe_info)) { safe_chr(' ', tbuf, &tp); safe_str_space(current, tbuf, &tp); if (GoodObject(who)) notify_format(player, T("%s can't hear you."), AName(who, AN_SYS, NULL)); } else { /* A good whisper */ good[gcount++] = who; if (gcount >= 100) { notify(player, T("Too many people to whisper to.")); break; } } } *tp = '\0'; if (*tbuf) notify_format(player, T("Unable to whisper to:%s"), tbuf); if (!gcount) { mush_free(tbuf, "string"); return; } /* Drunk wizards... */ if (Dark(player)) noisy = 0; /* Set up list of good names */ tp = tbuf; safe_str(T(" to "), tbuf, &tp); for (who = 0; who < gcount; who++) { if (noisy && (get_random32(0, 100) < (uint32_t) WHISPER_LOUDNESS)) overheard = 1; safe_itemizer(who + 1, (who == gcount - 1), ",", T("and"), " ", tbuf, &tp); safe_str(AName(good[who], AN_SAY, NULL), tbuf, &tp); } *tp = '\0'; if (key == 1) { notify_format(player, (gcount > 1) ? T("%s sense: %s%s%s") : T("%s senses: %s%s%s"), tbuf + 4, AName(player, AN_SAY, NULL), gap, arg2); p = tprintf("You sense: %s%s%s", AName(player, AN_SAY, NULL), gap, arg2); } else { notify_format(player, T("You whisper, \"%s\"%s."), arg2, tbuf); p = tprintf(T("%s whispers%s: %s"), AName(player, AN_SAY, NULL), gcount > 1 ? tbuf : "", arg2); } strcpy(sname, AName(player, AN_SAY, NULL)); for (who = 0; who < gcount; who++) { notify_must_puppet(good[who], p); if (Location(good[who]) != Location(player)) overheard = 0; } if (overheard) { dbref first = Contents(Location(player)); if (!GoodObject(first)) return; p = tprintf(T("%s whispers%s."), sname, tbuf); DOLIST(first, first) { overheard = 1; for (who = 0; who < gcount; who++) { if ((first == player) || (first == good[who])) { overheard = 0; break; } } if (overheard) notify_noecho(first, p); } }