/* functions.c - MUSH function handlers */ /* $Id: functions.c,v 1.174 2003/02/24 18:05:22 rmg Exp $ */ #include "copyright.h" #include "autoconf.h" #include "config.h" #include "alloc.h" /* required by mudconf */ #include "flags.h" /* required by mudconf */ #include "htab.h" /* required by mudconf */ #include "mudconf.h" /* required by code */ #include "db.h" /* required by externs */ #include "externs.h" /* required by interface */ #include "command.h" /* required by code */ #include "match.h" /* required by code */ #include "attrs.h" /* required by code */ #include "powers.h" /* required by code */ #include "functions.h" /* required by code */ #include "fnproto.h" /* required by code */ extern int FDECL(parse_ext_access, (int *, EXTFUNCS **, char *, NAMETAB *, dbref, char *)); extern NAMETAB access_nametab[]; UFUN *ufun_head; const Delim SPACE_DELIM = { 1, " " }; void NDECL(init_functab) { FUN *fp; hashinit(&mudstate.func_htab, 250 * HASH_FACTOR, HT_STR|HT_KEYREF); for (fp = flist; fp->name; fp++) { hashadd((char *)fp->name, (int *)fp, &mudstate.func_htab, 0); } ufun_head = NULL; hashinit(&mudstate.ufunc_htab, 15 * HASH_FACTOR, HT_STR); } void do_function(player, cause, key, fname, target) dbref player, cause; int key; char *fname, *target; { UFUN *ufp, *ufp2; ATTR *ap; char *np, *bp; int atr, aflags; dbref obj, aowner; /* Check for list first */ if (key & FUNCT_LIST) { if (fname && *fname) { /* Make it case-insensitive, and look it up. */ for (bp = fname; *bp; bp++) { *bp = tolower(*bp); } ufp = (UFUN *) hashfind(fname, &mudstate.ufunc_htab); if (ufp) { notify(player, tprintf("%s: #%d/%s", ufp->name, ufp->obj, ((ATTR *) atr_num(ufp->atr))->name)); } else { notify(player, tprintf("%s not found in user function table.", fname)); } return; } /* No name given, list them all. */ for (ufp = (UFUN *) hash_firstentry(&mudstate.ufunc_htab); ufp != NULL; ufp = (UFUN *) hash_nextentry(&mudstate.ufunc_htab)) { notify(player, tprintf("%s: #%d/%s", ufp->name, ufp->obj, ((ATTR *) atr_num(ufp->atr))->name)); } return; } /* Make a local uppercase copy of the function name */ bp = np = alloc_sbuf("add_user_func"); safe_sb_str(fname, np, &bp); *bp = '\0'; for (bp = np; *bp; bp++) *bp = toupper(*bp); /* Verify that the function doesn't exist in the builtin table */ if (hashfind(np, &mudstate.func_htab) != NULL) { notify_quiet(player, "Function already defined in builtin function table."); free_sbuf(np); return; } /* Make sure the target object exists */ if (!parse_attrib(player, target, &obj, &atr, 0)) { notify_quiet(player, NOMATCH_MESSAGE); free_sbuf(np); return; } /* Make sure the attribute exists */ if (atr == NOTHING) { notify_quiet(player, "No such attribute."); free_sbuf(np); return; } /* Make sure attribute is readably by me */ ap = atr_num(atr); if (!ap) { notify_quiet(player, "No such attribute."); free_sbuf(np); return; } atr_get_info(obj, atr, &aowner, &aflags); if (!See_attr(player, obj, ap, aowner, aflags)) { notify_quiet(player, NOPERM_MESSAGE); free_sbuf(np); return; } /* Privileged functions require you control the obj. */ if ((key & FUNCT_PRIV) && !Controls(player, obj)) { notify_quiet(player, NOPERM_MESSAGE); free_sbuf(np); return; } /* See if function already exists. If so, redefine it */ ufp = (UFUN *) hashfind(np, &mudstate.ufunc_htab); if (!ufp) { ufp = (UFUN *) XMALLOC(sizeof(UFUN), "do_function"); ufp->name = XSTRDUP(np, "do_function.name"); for (bp = (char *)ufp->name; *bp; bp++) *bp = toupper(*bp); ufp->obj = obj; ufp->atr = atr; ufp->perms = CA_PUBLIC; ufp->next = NULL; if (!ufun_head) { ufun_head = ufp; } else { for (ufp2 = ufun_head; ufp2->next; ufp2 = ufp2->next) ; ufp2->next = ufp; } if (hashadd(np, (int *) ufp, &mudstate.ufunc_htab, 0)) { notify_quiet(player, tprintf("Function %s not defined.", fname)); XFREE(ufp->name, "do_function"); XFREE(ufp, "do_function.2"); free_sbuf(np); return; } } ufp->obj = obj; ufp->atr = atr; ufp->flags = 0; if (key & FUNCT_NO_EVAL) ufp->flags |= FN_NO_EVAL; if (key & FUNCT_PRIV) ufp->flags |= FN_PRIV; if (key & FUNCT_PRES) ufp->flags |= FN_PRES; free_sbuf(np); if (!Quiet(player)) notify_quiet(player, tprintf("Function %s defined.", fname)); } /* --------------------------------------------------------------------------- * list_functable: List available functions. */ void list_functable(player) dbref player; { FUN *fp, *modfns; UFUN *ufp; char *buf, *bp; MODULE *mp; buf = alloc_lbuf("list_functable"); bp = buf; safe_str((char *)"Built-in functions:", buf, &bp); for (fp = flist; fp->name; fp++) { if (Check_Func_Access(player, fp)) { safe_chr(' ', buf, &bp); safe_str((char *) fp->name, buf, &bp); } } notify(player, buf); WALK_ALL_MODULES(mp) { if ((modfns = DLSYM_VAR(mp->handle, mp->modname, "functable", FUN *)) != NULL) { bp = buf; safe_tprintf_str(buf, &bp, "Module %s functions:", mp->modname); for (fp = modfns; fp->name; fp++) { if (Check_Func_Access(player, fp)) { safe_chr(' ', buf, &bp); safe_str((char *) fp->name, buf, &bp); } } notify(player, buf); } } bp = buf; safe_str((char *)"User-defined functions:", buf, &bp); for (ufp = ufun_head; ufp; ufp = ufp->next) { if (check_access(player, ufp->perms)) { safe_chr(' ', buf, &bp); safe_str(ufp->name, buf, &bp); } } notify(player, buf); free_lbuf(buf); } /* --------------------------------------------------------------------------- * list_funcaccess: List access on functions. */ static void helper_list_funcaccess(player, fp, buff) dbref player; FUN *fp; char *buff; { char *bp; int i; while (fp->name) { if (Check_Func_Access(player, fp)) { if (!fp->xperms) { sprintf(buff, "%s:", fp->name); } else { bp = buff; safe_str((char *) fp->name, buff, &bp); safe_chr(':', buff, &bp); for (i = 0; i < fp->xperms->num_funcs; i++) { if (fp->xperms->ext_funcs[i]) { safe_chr(' ', buff, &bp); safe_str(fp->xperms->ext_funcs[i]->fn_name, buff, &bp); } } } listset_nametab(player, access_nametab, fp->perms, buff, 1); } fp++; } } void list_funcaccess(player) dbref player; { char *buff; FUN *ftab; UFUN *ufp; MODULE *mp; buff = alloc_sbuf("list_funcaccess"); helper_list_funcaccess(player, flist, buff); WALK_ALL_MODULES(mp) { if ((ftab = DLSYM_VAR(mp->handle, mp->modname, "functable", FUN *)) != NULL) { helper_list_funcaccess(player, ftab, buff); } } for (ufp = ufun_head; ufp; ufp = ufp->next) { if (check_access(player, ufp->perms)) { sprintf(buff, "%s:", ufp->name); listset_nametab(player, access_nametab, ufp->perms, buff, 1); } } free_sbuf(buff); } /* --------------------------------------------------------------------------- * cf_func_access: set access on functions */ CF_HAND(cf_func_access) { FUN *fp; UFUN *ufp; char *ap; for (ap = str; *ap && !isspace(*ap); ap++) ; if (*ap) *ap++ = '\0'; for (fp = flist; fp->name; fp++) { if (!string_compare(fp->name, str)) { return (parse_ext_access(&fp->perms, &fp->xperms, ap, (NAMETAB *) extra, player, cmd)); } } for (ufp = ufun_head; ufp; ufp = ufp->next) { if (!string_compare(ufp->name, str)) { return (cf_modify_bits(&ufp->perms, ap, extra, player, cmd)); } } cf_log_notfound(player, cmd, "Function", str); return -1; }