/* cyber.c * - square@cco.caltech.edu * adopted from the "old" tracer in lpmud < 2.x * - it can now support many-arguments calling (up to 6) * - argument could be any type, even array and map! (well, by a little trick) * - for <item>, file representation could have wildcards, as long as * it is a unique file representation. * - the Recipient <item> of Call could be an array of objects * (again by using wildcards) * - It's incorporated into lsc, becoming a programmable tracer * (THE ULTIMATE CYBER EYE!) */ #include <mudlib.h> /* #include <lsc.h> */ #include "/u/s/square/lsc/lsc.h" inherit OBJECT ; /* inherit LSC ; */ inherit "u/s/square/lsc/lsc2"; #define MAXARGS 6 string * query_list; string * efun_list; mixed * Parse_List(string str); mixed parse_object_list(string str); void assign(mixed var,mixed val); static void disp(object ob); int Call(string str); string * init_efun(); print_ret(mixed ret, int layer); string repeat_str(string ch, int n) { return sprintf("%'"+ch+"':*s",n,""); } string format_mixed(mixed data, int len) { int n; string tmp; if (undefinedp(data)) { tmp = "<null>"; n = strlen(tmp); if (n>len) return repeat_str("*",len); return sprintf("%|:*s", len, tmp); } if (!data || intp(data) ) { tmp = data+" "; n = strlen(tmp); if (n>len) return repeat_str("*",len); return sprintf("%:*s", len, tmp); } if (stringp(data)) { n = strlen(data); if (n>len) return data[0..len-4]+" .."; return sprintf("%-:*s",len,data); } if (objectp(data)) { tmp = file_name(data); n = strlen(tmp); if (n>len) return tmp[0..len-4]+" .."; return sprintf("%-:*s",len,tmp); } if (mapp(data)) { tmp = "<mapp>"; n = strlen(tmp); if (n>len) return repeat_str("*",len); return sprintf("%|:*s", len, tmp); } if (pointerp(data)) { tmp = "<array>"; n = strlen(tmp); if (n>len) return repeat_str("*",len); return sprintf("%|:*s", len, tmp); } /* error */ return repeat_str("X",len); } int Clean(string str) { object *oblist; mixed ob; int i,n; int all_done; all_done = 0; if (!str) return 0; ob = parse_object_list(str); if (!ob || !objectp(ob)) return 0; while(!all_done) { all_done = 1; oblist = all_inventory(ob); n = sizeof(oblist); for(i=0;i<n;i++) { if (query_ip_number(oblist[i])) continue; oblist[i]->remove(); all_done = 0; } } write("Ok.\n"); return 1; } int Destruct(string str) { mixed mark; if (!str) return 0; mark = parse_object_list(str); if (!mark || !objectp(mark)) return 0; mark->remove(); if (mark) destruct(mark); write("Ok.\n"); return 1; } int Trans(string str) { mixed mark; if (!str) return 0; mark = parse_object_list(str); if (!mark || !objectp(mark)) return 0; mark->move(environment(this_player())); write("Ok.\n"); return 1; } string *init_query() { if (query_list) return query_list; query_list = ({ "name", "ghost","npc","wizard", "email", "hit_points", "max_hp", "spell_points", "max_sp", "time_to_heal", "race", "armor_class", "wealth", "stat", "weapon1", "weapon2", "armor", "bulk", "mass", "capacity", "invis", "title", "type", "value", "damage", "weapon", "gender", } ); return query_list; } static object find_item(object prev, string str) { object ob; string tmp; int num; if (str == "here") return environment(this_player()); if (str=="me") return this_player(); if (str=="EYE") return this_object(); if (str == "^") return environment(prev); if (sscanf(str, "@%s", tmp) == 1) return find_living(tmp); if (sscanf(str, "*%s", tmp) == 1) return find_player(tmp); if (sscanf(str, "/%s", tmp) == 1 || sscanf(str, "~%s", tmp) == 1) { string *matched, file; int n; if (str[0]=='/' && (ob=find_object(str))) return ob; if (sscanf(str,"%s#%d",file,n)==2) { matched = (string *)this_player()->wild_card(file+".c"); if (sizeof(matched)!=1) { write("Ambiguous\n"); return 0; } return find_object(matched[0][0..strlen(matched[0])-3]+ "#"+n); } matched=(string *) this_player()->wild_card(str+".c"); if (sizeof(matched)!=1) { write("Ambiguous.\n"); return 0; } call_other(matched[0],"??"); return find_object(matched[0]); } if (sscanf(str, "$%d", num) == 1) { object * u; u = users(); write("size: " + sizeof(u) + "\n"); if (num >= sizeof(u) || num < 0) return 0; return u[num - 1]; } if (sscanf(str, "$%s", tmp) == 1) { return _varlist[tmp]; } if (prev == 0) prev = environment(this_player()); if (sscanf(str, "\"%s\"", tmp) == 1) { ob = first_inventory(prev); while(ob && (string) ob->query("short") != tmp) { ob = next_inventory(ob); } return ob; } if (sscanf(str, "#%d", num) == 1) { if (prev == 0) return 0; ob = first_inventory(prev); while(num > 1) { num -= 1; if (ob == 0) return 0; ob = next_inventory(ob); } return ob; } /* this part is adopted from the code of huthar@tmi */ if(ob = present(str, prev)) return ob; tmp = resolv_path( (string)this_player()->get_path(), str); if(file_size(tmp+".c") < 0) return 0; call_other(tmp,"???"); /* Force load */ return find_object(tmp); } mixed parse_object_list(string str) { string tmp, rest; object prev; prev = environment(this_player()); while(prev && str) { if (sscanf(str, "%s:%s", tmp, rest) == 2) { prev = find_item(prev, tmp); str = rest; continue; } prev = find_item(prev, str); break; } assign("$", prev); if (objectp(prev)) disp(prev); return prev; } static void disp(object ob) { write(file_name(ob) + "\n"); } int Goto(string str) { mixed mark; if (!str) return 0; mark = parse_object_list(str); if (!mark || !objectp(mark)) return 0; say((string)this_player()->query_mmout()+".\n"); this_player()->move(mark); say((string)this_player()->query_mmin()+".\n"); write("Ok.\n"); return 1; } int Efun(string str) { string *words; if (!str) return 0; words = explode(str+" "," "); if (member_array(words[0],efun_list)!=-1) { words[0] = capitalize(words[0]); return Call( "EYE "+implode(words," ") ); } write("Efun "+words[0]+" is not supported\n"); return 1; } int In(string str) { string path, cmd; object old_ob; mixed ob; if (!str) return 0; if (sscanf(str, "%s %s", path, cmd) != 2) return 0; ob = parse_object_list(path); if (!ob || !objectp(ob)) return 0; old_ob = environment(this_player()); this_player()->move(ob); seteuid(getuid(this_player())); this_player()->force_me(cmd); this_player()->move(old_ob); return 1; } int Anew(string str) { string file, error; int num; object newob, original; if (sscanf(file_name(this_object()),"%s#%d",file,num)!=2) return 0; seteuid(getuid(this_player())); original = find_object(file); if (original) destruct(original); error = catch(call_other(file,"???")); if (error) { write(error+"\n"); return 1; } newob = new(file); newob->move(this_player()); write("The cyber refreshes itself.\n"); ::remove(); return 1; } int move(object dest) { if (wizardp(dest)) return ::move(dest); return 1; } void init() { if (!wizardp(this_player())) destruct(this_object()); add_action("help", "help"); add_action("Dump", "Dump"); add_action("Destruct", "Destruct"); add_action("Call", "Call"); /* Tell could be accomplished by Call obj catch_tell ... */ add_action("Trans", "Trans"); add_action("Set", "Set"); add_action("Goto", "Goto"); add_action("In", "In"); add_action("Clean", "Clean"); add_action("Efun", "Efun"); add_action("Extract", "Extract"); add_action("Anew", "Anew"); add_action("compile", "Run"); add_action("compile", ">"); add_action("lighton","light"); } int help(string str) { if (str == "eye") { write("Commands available:\n\n"); write("Goto <item>, Dump [<item> [list]],\n"+ "Destruct <item>, Trans <item>, In <item> command,\n"+ "Clean <item>, Anew,\n"+ "Call <item> <function> [arg1] [arg2] ...\n"+ "Set <var_name> <arg>\n"+ "Efun <efun_name> [arg1] [arg2]...\n"+ "Extract <varname> <from> [to]\n"+ "Run <LSC language> (or use '>' instead of 'Run'\n"); write("DO 'help eye commands|item|arg' FOR MORE INFORMATION\n"); return 1; } if (str == "eye funcation" || str == "eye <function>") { write("see 'help eye Call'\n"); return 1; } if (str == "eye [arg]" || str == "eye arg" || str == "eye argument") { write("arguments are in the form:\n"+ " *<item>,\n"+ " string_with_no_space,\n"+ " \"string with spaces\",\n"+ " integer, or\n"+ " { argument_1 argument_2 ... }\n"); return 1; } if (str == "eye item" || str == "eye <item>" ) { write("An item is a list separated by ':'. An item in that e\n"); write("@name\tName of a player or monster.\n"); write("*name\tName of player only. Can be invisible.\n"); write("/obj or ~obj\tfile name of an object.\n"); write(" IMPORTANT: file name can have \"#%d\""+ " and wildcards \"*\".\n"); write("$var\tContents of a variable.\n"); write(" ($$ will give last item used)\n"); write("$num\tPlayer number 'num' in users() array.\n"); write("here\tThis room.\n"); write("#num\tThe 'num'th inventory inside this room or\n"); write(" the item surrounding it by a ':'\n"); write("id\tName of an item.\n"); write("me\tYourself.\n"); return 1; } if (str == "eye Call") { write("e.g:\n"+ "Call *square:#1 testing_function 1 \"hello world\"\n"+ " This command looks for the first inventory inside\n"+ " the player named 'square' and call the function\n"+ " 'testing_function' inside it with arguments: integer 1\n"+ " and string \"hello world\"\n"); write("Call *square:#1 move **deadman\n"+ " This command calls the move() function of square's\n"+ " 1st inventory with the argument: object (deadman's obj)\n"+ " [NOTE: this normally teleports the thing to deadman's\n"+ " inventory]\n"); write("Call ~sq*/c* foobar {1 2 \"three four\"}\n"+ " This command calls ALL objects with matched filename\n"+ " EXCEPT cloned objects (with \"#dddd\" suffix)\n"+ " Though not recommended for massive calling, it may come\n"+ " in handy when you're dealing with long filenames\n"); return 1; } if (str == "eye Dump") { write("e.g:\n"+ "Dump me list\n"+ " This display every inventory of the command giver.\n"+ "Dump\n"+ " This shows the variables remembered by the eye.\n"); return 1; } if (str == "eye Destruct") { write("Destruct object specified by <item>.\n"+ "See also 'help eye item'\n"); return 1; } if (str == "eye Goto") { write("Goto the <item>'s inventory.\n"+ "See also 'help eye item'\n"); return 1; } if (str == "eye Trans") { write("Summon the <item> to your environment.\n"+ "See also 'help eye item'\n"); return 1; } if (str == "eye In") { write("Perform the <command> inside <item>.\n"+ "See also 'help eye item'\n"); return 1; } if (str == "eye Clean") { write("Destruct all non-interactive objs inside <item>.\n"+ "See also 'help eye item'\n"); return 1; } if (str == "eye Set") { write("e.g:\n"+ "Set one 1\n"+ "Set home *~square/workroom\n"+ " This 2 commands set up 2 variables,'one' and 'home'\n"+ " So, when you need to do something like:\n"+ " Call dummy_object test_function 1 *~square/workroom\n"+ " you can as well do this:\n"+ " Call dummy_object test_function $one $home\n"); return 1; } if (str == "eye Efun") { int i,n; n = sizeof(efun_list); write("Efun is just like Call, but it calls efuns\n"+ "instead of object-declared functions.\n"+ "FUNCTIONS SUPPORTED RIGHT NOW:\n"); for(i=0;i<n;i++) { write(efun_list[i]+"\n"); } return 1; } if (str == "eye Extract") { write("Manipulate array variables\n"); return 1; } if (str == "eye Run" || str == "eye >") { write("e.g:\n"+ "Run /! {dup dup 1 le {pop pop 1} {1 sub ! mul} ifelse } def\n"+ " This defines a recursive factorial function, so you may\n"+ " then have:\n"+ "Run 4 ! say\n"+ " which tells you the result to be 24\n"); return 1; } return 0; } varargs int Dump(string str) { int tmp, i,j,n; object tmpob; string flag, path, * ky; string tmpstr; string qu; mixed ob, tmpmixed; if (!str) { write("All variables:\n"); ky = keys(_varlist); n = sizeof(ky); for (i=0;i<n;i++) { printf("%-:10s %s",ky[i], format_mixed(_varlist[ky[i]],30)); if (objectp(_varlist[ky[i]])) { write(format_mixed(getuid(_varlist[ky[i]]), 15)+" "+ format_mixed(geteuid(_varlist[ky[i]]),15) ); } write("\n"); } return 1; } if (sscanf(str, "%s %s", path, flag) != 2) path = str; ob = parse_object_list(path); if (!ob) return 0; if (!objectp(ob) ) { print_ret(ob,0); return 1; } if (flag == "list") { ob = first_inventory(ob); if (!ob) { write("Nothing in it\n"); return 1; } write(format_mixed("#",3)+format_mixed("file name",30) + format_mixed("short desc",20)+format_mixed("uid",10)+ format_mixed("euid",10)+"\n"); while(ob) { i += 1; write( format_mixed(i + ":", 3) ); write( format_mixed(ob, 30) ); write( format_mixed((string) ob->query("short"), 20)); write( format_mixed( getuid(ob),10)+ format_mixed(geteuid(ob),10) +"\n" ); ob = next_inventory(ob); } return 1; } write(file_name(ob)); write(":\n"); write((string) ob->query("short") ); if (living(ob)) write(" (living) "); if (tmpstr = query_ip_number(ob)) write("(interactive) '" + query_ip_number(ob) + "' "); write("\n"); if (tmpstr) write("query_idle:\t\t" + query_idle(ob) +"@" +query_ip_name(ob)+"\n"); tmpob = query_snoop(ob); if (tmpob) write("Snooped by " + format_mixed(tmpob,20) + "\n"); for(i=0;i<sizeof(query_list);i++) { tmpmixed = (mixed) ob->query(query_list[i]); if (!undefinedp(tmpmixed)) { write(format_mixed(query_list[i]+":",25)); print_ret(tmpmixed,1); } } return 1; } void call_usage() { write("Usage: Call <item> <func> [*item|[\"]string[\"]|integer] ...\n"); } mixed * Parse_Arguments(string str) { int i,j, part; mixed * ret; string tmp1, tmp2, current, rest; if (!str) return ({}); while(sscanf(str," %s",str)); if (str=="") return ({}); if (str[0]=='\"') { for(j=1;j<strlen(str);j++) { if(str[j]=='\\'&& j<strlen(str)-1 ) { tmp1=j>1?str[0..j-1]:""; tmp2=j<strlen(str)-2?str[j+2..strlen(str)-1]:""; if(str[j+1]=='n') { str=tmp1+"\n"+tmp2; } else if(str[j+1]=='t') { str=tmp1+"\t"+tmp2; } else { str = tmp1+str[j+1..j+1]+tmp2; } continue; } if (str[j]=='\"') { if(j==1) ret=({""}); else ret=({str[1..j-1]}); if(j==strlen(str)-1) { str=""; } else { str=str[j+1..strlen(str)-1]; } return ret+Parse_Arguments(str); } } write("Cyber eye: incomplete string input\n"); return 0; } if (str[0]=='{') { /*array*/ part = Look_for_char(str,'{','}'); if (part==-1) { write("Cyber eye: incomplete array input\n"); return 0; } if (part==1) ret=({ ({}) }); else ret = ({ Parse_Arguments(str[1..part-1]) }); if (part==strlen(str)-1) { rest=""; } else { rest=str[part+1..strlen(str)-1]; } return ret + Parse_Arguments(rest); } if (sscanf(str,"%s %s",current, rest)!=2) { current = str; rest = ""; } if (sscanf(current,"%d", i)) return ({ i }) + Parse_Arguments(rest); if (strlen(current)>2 && sscanf(current,"*%s",tmp1)) return ({ parse_object_list(tmp1) })+Parse_Arguments(rest); return ({ current })+Parse_Arguments(rest); } int Call(string str) { string item, with, rest, argstr, tmp; mixed * ob; mixed * args; int i,m,n; int ret; if (!str || !sscanf(str,"%s %s", item, rest) || !rest) { call_usage(); return 1; } seteuid(getuid(this_player())); sscanf(rest, "%s %s", with, argstr); if (!argstr || argstr=="") with = rest; if (!with) { call_usage(); return 1; } ob = Parse_List(item) - ({0}); if (!(m=sizeof(ob))) { write("Can't find target.\n"); return 1; } args = Parse_Arguments(argstr) ; if (!args) return 1; n = sizeof(args); if (n<MAXARGS) args = args + allocate(MAXARGS-n); write("Processing object list of size "+m+".\n"); write("Function: "+with+"("); for(i=0;i<n;i++) { if (i) write(","); if (stringp(args[i])) write("\""+args[i]+"\""); else if (pointerp(args[i])) write(dump_variable(args[i])); else if (objectp(args[i])) write(file_name(args[i])); else write(args[i]); } write(")\n"); for(i=0;i<m;i++) { ret = (mixed) call_other(ob[i], with, args[0], args[1], args[2], args[3], args[4], args[5]); if ( ( objectp(ob[i]) && !function_exists(with,ob[i])) || ( stringp(ob[i]) && (ob[i]=find_object(ob[i])) && ob[i] && !function_exists(with,ob[i])) ) { write("Warning: Function "+with+" does not exist in "); write(file_name(ob[i])); write("\n"); if (ret) { write("Diagnosis: object shadowed => "); print_ret(ret,0); } } else { write("=> "); print_ret(ret,0); } } assign("ret", ret); return 1; } mixed * Parse_List(string str) { string tmp1, tmp2, tail, *filelist; int tmp3; object list; int i,n; if ((str[0]=='/'||str[0]=='~') && !sscanf(str,"%s:%s",tmp1,tmp2) && !sscanf(str,"%s#%d",tmp1,tmp3) && sscanf(str,"%s*%s",tmp1,tmp2) ) { n=strlen(str); tail=str[(n-2)..(n-1)]; if (tail!=".c" && tail!="*c" && str[n-1]!='*' ) str+=".c"; filelist= (string *)this_player()->wild_card(str); print_ret(filelist,0); return filelist; } return ({ parse_object_list(str) } ); } print_ret(mixed ret,int layer) { int i,n; mixed * k; if (layer) { printf("%-:*s",layer*2," "); } if (undefinedp(ret)) write("<NULL>\n"); else if (intp(ret)) write(ret + "\n"); else if (pointerp(ret)) { n=sizeof(ret); write("Array of size " + n + "\n"); for(i=0;i<n;i++) print_ret(ret[i],layer+1); } else if (stringp(ret)) write("\"" + ret + "\"\n"); else if (objectp(ret)) { write("Obj:"); write(format_mixed(ret,25)+ format_mixed((string)ret->query("short"),20) + format_mixed(getuid(ret),7)+format_mixed(geteuid(ret),7)); write("\n"); } else if (mapp(ret)) { k=keys(ret); n = sizeof(k); write("Mapping of size "+n+"\n"); for(i=0;i<n;i++) { write(" "[0..(layer*2+1)]); write(k[i]); write(":"); print_ret(ret[k[i]],layer+1); } } } int Set(string str) { object ob; mixed * args; string item, var; int n; if (!str) return 0; if (sscanf(str, "%s %s", var, item) != 2) return 0; args = Parse_Arguments(item); if (!args) return 1; n = sizeof(args); if (n!=1) { write("Can't assign more than 1 values"); return 1; } assign(var, args[0]); write("Ok.\n"); return 1; } void assign(mixed var, mixed val) { _varlist[var]=val; } create() { set("id", ({ "eye", "trace", "tracer", "cyber eye", "cyber" } ) ); set("short","Cyber Eye"); set("long","@@query_long"); query_list = init_query(); efun_list = init_efun(); LSC_create(); Reset(); } string query_long() { int i,n,stat; string statstr; n = number_of_children(); write("You check the current status of the cyber eye:\n"); if (_status==IDLE) statstr="Idle"; else if (_status==RUNNING) statstr="Running"; else if (_status==INCOMPLETE_INPUT) statstr="Incomplete input"; else if (_status==PAUSED) statstr="Paused"; else if (_status==ERROR) statstr="Error"; printf("Status: %s, Stack size: %d\nInput:%-:70O\n", statstr, _stack_ptr, _pending_input); if (n) { printf("Background job:(%d in total)\n",n); printf("%:3s %|:35s %|:15s %:3s %-:20s\n", "#", "OBJ", "id", "Stk", "Input"); for(i=0;i<n;i++) { if (_children[i]) printf("%:3d %-:35O %-:15s %:3d %-:20s\n", i, _children[i], (string)_children[i]->query_process_id(), (int) _children[i]->query_stack_ptr(), (string) _children[i]->query_input() ); } } return "Type \"help eye\" for how to use this cyber eye.\n"; } void self_destruct() { tell_object(environment(this_object()), "The Cyber Eye suddenly gets warm.\n"); call_out("self_destruct2", 2); } void self_destruct2() { tell_object(environment(this_object()), "The Cyber Eye disappears in a flash of light.\n"); destruct(this_object()); } /* fool-proof query_auto_load(). It works everywhere. */ string query_auto_load() { string full, file; int num; full = file_name(this_object()); if (sscanf(full,"%s#%d", file, num)) full = file; return full+":0"; } init_arg(string arg) { return; } string *init_efun() { if (efun_list) return efun_list; efun_list = ({ "users", "dump_variable", "resolv_path", "children", "sprintf", "call_out_info", "inherit_list", } ); return efun_list; } Users() { return users(); } string Dump_variable(mixed data) { return dump_variable(data); } string Resolv_path(string curr, string new) { return resolv_path(curr, new); } int Extract(string str) { mixed * args; string var; int i,j,n,element; element = 0; if (!str) return 0; if (sscanf(str, "%s %d %d", var, i,j) != 3) { if (sscanf(str, "%s %d", var,i)==2) { j=i; element = 1; } else { write("usage: Extract <varname> <from> [to]\n"); return 1; } } args = _varlist[var]; if (!pointerp(args)) { write("variable "+var+" is not an array\n"); return 1; } n = sizeof(args); if (!n) { write("Empty Array\n"); return 1; } if (j<i || i<0 || j>=n) { write("Out of range\n"); return 1; } if (element) assign("$", args[i]); else assign("$", args[i..j]); write("Ok.\n"); return 1; } int lighton(string str) { if (str=="on") set_light(1); if (str=="off") set_light(-1); return 1; } object * Children(string ob) { return children(ob); } string Sprintf(string fmt, mixed a1,mixed a2,mixed a3,mixed a4, mixed a5) { #ifdef SECURE write("secure!\n"); #endif return sprintf(fmt,a1,a2,a3,a4,a5); } mixed * Call_out_info() { return call_out_info(); } string * Inherit_list(object ob) { return inherit_list(ob); } remove() { :: remove(); } int compile(string str) { Compile(str); return 1; } int _cmd() { mixed i; object env; i = Pop(); if (!Is_String(i)) { error("_cmd: Illegal argument"); return -1; } i = Parse_String(i); env = environment(this_object()); if (!env) { ::remove(); return -1; } environment()->force_me(i); _count = 0; } int _say() { mixed i; object env, ob; string out; i = Pop(); env = environment(this_object()); if (!env) return 0; _counter = 0; if (Is_String(i)) { out = Parse_String(i); } else if (Is_Object(i)) { ob = find_object(i[2..strlen(i)-1]); if (!ob) out = "<null object>"; else out = file_name(ob); } else if (objectp(i)) { if (!i) out = "<null object>"; else out = file_name(i); } else if (intp(i)) { out = ""+i; } else if (pointerp(i)) { out = Restore_Array(i); } if (out) { tell_object(env, "cyber eye: "+out+"\n"); return 0; } return 0; } error(string str) { tell_object(environment(this_object()), "CYBER EYE ERROR: "+str+"\n"); _status = ERROR; }