/* Copyright (C)1991, Marcus J. Ranum. All rights reserved. */ #ifndef lint static char RCSid[] = "$Header: /usr/users/mjr/hacks/umud/RCS/util.c,v 1.4 91/08/29 17:24:13 mjr Exp $"; #endif /* configure all options BEFORE including system stuff. */ #include "config.h" #include <ctype.h> #include <varargs.h> #include "mud.h" #include "vars.h" /* this file contains useful routines that do a somewhat higher-level manipulation on objects and their attributes, etc. since attributes are typed, for example, it's a waste of code for each player command that gets an attribute to have to check types. there are functions in here to get attributes of specific types, add to lists and make sure the attribute being added to is a list, etc, etc. typically, most player-command code, unless something really low-level is needed, will be programmed with stuff out of this file. most of these routines operate in a "user context" - rather than a lower-level. for example, error messages get written to the user, types are checked, permissions are checked, etc. */ /* return nonzero if the object-ID given is well-formed. */ int ut_isgoodid(v) char *v; { if(!strcmp(v,system_object)) return(1); while(1) { if(!isdigit(*v)) { /* pure numeric */ if(*v == '\0') return(1); /* fully qualified - strip out '@' and keep looking */ if(*v != '@') return(0); v++; /* hunt to end of string */ while(*v != '\0') { if(!isalnum(*v) && *v != '_') return(0); v++; } return(1); } v++; } } /* make an object fully-qualified addressed. */ ut_delocaliz(o1) char *o1; { char *p = o1; char *q; while(*p != '\0') { if(*p == '@') return(0); p++; } *p++ = '@'; for(q = mud_getname(); *q != '\0';) *p++ = *q++; *p = '\0'; return(0); } ut_getnum(ob,att,ret) char *ob; char *att; int *ret; { char *ap; *ret = 0; if((ap = ut_getatt(ob,0,typ_int,att,(char *)0)) == (char *)0) return(-1); *ret = atoi(ap); return(0); } ut_setnum(who,ob,att,val) char *who; char *ob; char *att; int val; { char nbuf[128]; return(ut_set(who,ob,typ_int,att,itoa(val,nbuf))); } /* recursively look up attribute chains. The first parameter is the name of the object to look up, the second is the type of the attribute. the rest are the successive names of the attributes to chain off that attribute. so, for example: ut_getatt("342@here",flg,typ_str,attr_loc,attr_ply,(char *)0); would first try to access 342@here, then would look up the location attribute of that object, and IF AND ONLY IF that is an object id, it will look that up, and look for the player list of it. any failure will return (char *)0 if "flg" is set, the entire attribute (name and type) is returned. */ /* VARARGS3 */ char * ut_getatt(onam,flg,typ,va_alist) char *onam; int flg; char *typ; va_dcl { Obj *op; char *atp; char *nxt; va_list ap; if((op = cache_get(onam)) == (Obj *)0) return((char *)0); va_start(ap); if((atp = va_arg(ap,char *)) == (char *)0) return((char *)0); while(1) { if((atp = objattr(op,atp,(int *)0)) == (char *)0) return((char *)0); if((nxt = va_arg(ap,char *)) == (char *)0) break; if(!attistype(atp,typ_obj)) return((char *)0); if((atp = attdata(atp)) == (char *)0) return((char *)0); if((op = cache_get(atp)) == (Obj *)0) return((char *)0); atp = nxt; } va_end(ap); if(!attistype(atp,typ)) return((char *)0); if(flg) return(atp); return(attdata(atp)); } /* return nonzero if "who" has "flag" set */ ut_flagged(who,flag) char *who; char *flag; { return(ut_getatt(who,0,typ_flag,flag,(char *)0) != (char *)0); } /* return nonzero if "who" owns "what" */ ut_isobjown(who,what) char *who; char *what; { Obj *op; char *ap; if((op = cache_get(what)) == (Obj *)0) return(0); if((ap = objattr(op,var_owner,(int *)0)) == (char *)0) return(1); if(attistype(ap,typ_list) && lstlook(attdata(ap),who)) return(1); return(0); } /* set an object's attributes. this requires a context of who is running it, etc. */ int ut_set(who,onam,typ,anam,val) char *who; char *onam; char *typ; char *anam; char *val; { Obj *op; if((op = cache_get(onam)) == (Obj *)0) { say(who,onam," does not exist.\n",(char *)0); return(1); } if(objsetattr(op,typ,anam,val)) { say(who,"error writing to #",onam,"\n",(char *)0); return(1); } if(cache_put(op,onam)) { say(who,"error modifying #",onam,"\n",(char *)0); return(1); } return(0); } /* unset an object's attributes. this requires a context of who is running it, etc. */ int ut_unset(who,onam,anam) char *who; char *onam; char *anam; { Obj *op; if((op = cache_get(onam)) == (Obj *)0) { say(who,onam," does not exist.\n",(char *)0); return(1); } if(objunsetattr(op,anam)) { say(who,"error writing to #",onam,"\n",(char *)0); return(1); } if(cache_put(op,onam)) { say(who,"error modifying #",onam,"\n",(char *)0); return(1); } return(0); } /* add an item to the object's attribute list */ int ut_listadd(who,onam,anam,item) char *who; char *onam; char *anam; char *item; { char *ap; char *ins; if((ap = ut_getatt(onam,0,typ_list,anam,(char *)0)) == (char *)0) { ins = item; } else { if((ins = lstadd(ap,item,(int *)0)) == (char *)0) { say(who,"error adding to list.\n",(char *)0); return(1); } } if(ut_set(who,onam,typ_list,anam,ins)) { say(who,"error modifying object #",onam,".\n",(char *)0); return(1); } return(0); } /* drop an item from the object's attribute list */ int ut_listdel(who,onam,anam,item) char *who; char *onam; char *anam; char *item; { char *ap; char *ins; if((ap = ut_getatt(onam,0,typ_list,anam,(char *)0)) == (char *)0) return(0); if((ins = lstdel(ap,item,(int *)0)) == (char *)0) { say(who,"error dropping from list.\n",(char *)0); return(1); } /* list emptied? */ if(ins[0] == '\0' || (ins[0] == ';' && ins[1] == '\0')) { ut_unset(who,onam,anam); return(0); } if(ut_set(who,onam,typ_list,anam,ins)) { say(who,"error modifying object #",onam,".\n",(char *)0); return(1); } return(0); } /* create a new object ID and object, and return the ID to the player */ ut_objnew(who,rbuf,localflag) char *who; char *rbuf; int localflag; { Obj *op; int onum; char nxbuf[MAXOID]; rbuf[0] = '\0'; /* make an in-memory holder */ if((op = objnew()) == (Obj *)0) { say(who,"cannot create object.\n",(char *)0); return(1); } /* get the system high-object # */ if(ut_getnum(system_object,var_objcnt,&onum)) onum = 0; onum++; /* write it in the system object */ if(ut_setnum(who,system_object,var_objcnt,onum)) return(1); itoa(onum,nxbuf); /* if the object is not local-only, use FQON */ if(!localflag && ut_delocaliz(nxbuf)) return(1); /* make sure the object isn't there already!! */ if(cache_check(nxbuf)) { say(who,"WARNING - system free object count hosed\n",(char *)0); return(1); } /* add object to cache - NOTE - the cache routines will take care of eventually freeing the Obj * DO NOT FREE IT HERE!!!! */ if(cache_put(op,nxbuf)) { say(who,"cannot create #",nxbuf,"\n",(char *)0); return(1); } /* done! */ (void)strcpy(rbuf,nxbuf); return(0); } /* send a copy of the messages (va_list) to everyone in the room if "notme" is set, don't send a copy to that object */ /* VARARGS 2 */ void ut_roombcast(where,notme,va_alist) char *where; char *notme; va_dcl { char *in; char *atp; char nxtu[MAXOID]; va_list ap; if((in = ut_getatt(where,0,typ_list,var_ply,(char *)0)) == (char *)0) return; while((in = lstnext(in,nxtu)) != (char *)0) { if(notme != (char *)0 && !strcmp(nxtu,notme)) continue; va_start(ap); while((atp = va_arg(ap,char *)) != (char *)0) say(nxtu,atp,(char *)0); va_end(ap); } } /* return the location of the thing */ char * ut_loc(ob) char *ob; { char *ret; if((ret = ut_getatt(ob,0,typ_obj,var_loc,(char *)0)) != (char *)0) return(ret); return("nowhere"); } /* return the name of the thing, or the thing's objid if it is unnamed */ char * ut_name(ob) char *ob; { char *ret; if((ret = ut_getatt(ob,0,typ_str,var_nam,(char *)0)) != (char *)0) return(ret); return(ob); } int ut_setpass(obj,pass) char *obj; char *pass; { Obj *op; char pbuf[MAXOID]; if(strlen(pass) >= MAXOID) return(1); if((op = cache_get(obj)) == (Obj *)0) return(1); rot_init(obj); rot_encode(pass,pbuf); if(objsetattr(op,typ_str,var_pass,pbuf) || cache_put(op,obj)) return(1); return(0); } /* Figure out where 'home' is for this object. Sometimes this means limbo. */ ut_home(obj,dest) char *obj; char *dest; { char *home; char *mud; int i; home = ut_getatt(obj,0,typ_obj,var_home,(char *)0); /* We demand that home be fully qualified */ if(home == (char *)0 || (mud = index(home,'@')) == (char *)0) goto badhome; mud++; /* If it's not in cache, and belongs to this mud, extract the number */ if(!cache_check(home) && !strcmp(mud,mud_getname())){ for(i = 0; *home != '@' && i < MAXOID; i++) dest[i] = *home++; dest[i] = '\0'; } else { strcpy(dest,home); } if(!cache_check(dest)) goto badhome; return(1); badhome: /* Get limbo and use that as home */ home = ut_getatt(system_object,0,typ_obj,var_syslimbo,(char *)0); if(home == (char *)0) return(0); strcpy(dest,home); return(1); } /* returns where to put an object, assuming you'll want to use a dropto if there is one. */ char * ut_dropto(what,where,hm) char *what; char *where; char *hm; { char *drpto; int hashome; /* If it's homed to 'where', NO dropto */ if((hashome = ut_home(what,hm)) && !strcmp(hm,where)) return(where); drpto = ut_getatt(where,0,typ_obj,var_dropto,(char *)0); if(drpto == (char *)0) return(where); /* If the dropto is to 'home'.. */ if(!strcmp(drpto,"home")) return(hashome ? hm : where); return(drpto); } int ut_listchk(onam,anam,item) char *onam; char *anam; char *item; { return(lstlook(ut_getatt(onam,0,typ_list,anam,(char *)0),item)); }