Added public files
Roughly added all public files. Probably missed some, though.
diff --git a/obj/tools/MGtool/man.d/xcall b/obj/tools/MGtool/man.d/xcall
new file mode 100644
index 0000000..43e21ea
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xcall
@@ -0,0 +1,21 @@
+SYNOPSIS
+ xcall <object>-><function>(<expression>)
+
+DESCRIPTION
+ Calls the lfun <function> of the <object> with <expression> as
+ argument. The <properties.h> are included. Three objects are allready
+ defined on invokation. "me" represents the onwer of the Xtool. "here"
+ is the current room and "obj" is the object which lfun is called.
+ To use the object access syntax described above, a function called
+ "get(string)" can be used. If the call returned an object, the variable
+ "$result" will be set to this object.
+ xcall includes a private ~/.xtool.h, if it exists, to support user
+ defined macros.
+
+EXAMPLES
+ xcall $me->QueryProp(P_LONG)
+ xcall /std/thing#145->SetProp(P_SHORT,"a small thing")
+ xcall /secure/master->add_domain_wiz("hell", "hyp")
+ xcall $me->move(get("^deepthought"),"go")
+ (the last one uses the function get() to find the room where our god is)
+
diff --git a/obj/tools/MGtool/man.d/xcallouts b/obj/tools/MGtool/man.d/xcallouts
new file mode 100644
index 0000000..79adfa6
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xcallouts
@@ -0,0 +1,16 @@
+SYNOPSIS
+ xcallouts [search pattern]
+ or
+ xcallouts (when writing to a pipe)
+
+DESCRIPTION
+ With no argument it shows all your callouts. With a regexp as argument,
+ all matching callouts will be printed. When writing to a pipe, all
+ call_outs will be printed and the search pattern is not allowed.
+
+EXAMPLES
+ xcallouts obj Show all callouts with the string "obj" in it.
+ xcallouts . Show all callouts. Please never do this if it isn't
+ really neccessary. It just costs time - and what do you
+ want to do with this mass of information?
+
diff --git a/obj/tools/MGtool/man.d/xclean b/obj/tools/MGtool/man.d/xclean
new file mode 100644
index 0000000..dcc488e
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xclean
@@ -0,0 +1,12 @@
+SYNOPSIS
+ xclean [object]
+
+DESCRIPTION
+ Clean the inventory of the object, but don't destruct any living.
+ With no argument the current room will be cleaned. The objects
+ are removed with the lfun remove().
+
+EXAMPLE
+ xclean $me.bag
+ Clean my bag.
+
diff --git a/obj/tools/MGtool/man.d/xclone b/obj/tools/MGtool/man.d/xclone
new file mode 100644
index 0000000..00c1b7a
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xclone
@@ -0,0 +1,13 @@
+SYNOPSIS
+ xclone <filename>
+
+DESCRIPTION
+ Clones an object. On error, the error log file will be printed.
+ Moves the object (if possible) into your inventory. If the object
+ has been cloned successfully, the variable "$clone" will be set,
+ to make sure we don't lose the object out of sight :)
+
+EXAMPLE
+ xclone /std/thing
+ xcall $clone->SetShort("a BIG thing!");
+
diff --git a/obj/tools/MGtool/man.d/xdbg b/obj/tools/MGtool/man.d/xdbg
new file mode 100644
index 0000000..5609f2f
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xdbg
@@ -0,0 +1,14 @@
+SYNOPSIS
+ xdbg <object>
+
+DESCRIPTION
+ Prints out debug information buy using the efun debug_info().
+ Not all of these information is useful but it gives you information
+ of how many variables, functions, inherited objetcs and so on a object
+ has. It also shows if an object is living, if its heart beat is turned
+ on, when the next call of reset() will be (but don't take this value
+ not too seriously) etc.
+
+EXAMPLE
+ xdbg $me
+
diff --git a/obj/tools/MGtool/man.d/xdclean b/obj/tools/MGtool/man.d/xdclean
new file mode 100644
index 0000000..79f9093
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xdclean
@@ -0,0 +1,6 @@
+SYNOPSIS
+ xdclean <object>
+
+DESCRIPTION
+ Same as xclean, but makes a deep clean.
+
diff --git a/obj/tools/MGtool/man.d/xddes b/obj/tools/MGtool/man.d/xddes
new file mode 100644
index 0000000..a235645
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xddes
@@ -0,0 +1,6 @@
+SYNOPSIS
+ xddes <object>
+
+DESCRIPTION
+ Same as xdes, but makes a deep destruct.
+
diff --git a/obj/tools/MGtool/man.d/xdes b/obj/tools/MGtool/man.d/xdes
new file mode 100644
index 0000000..17bf984
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xdes
@@ -0,0 +1,8 @@
+SYNOPSIS
+ xdes <object>
+
+DESCRIPTION
+ Destruct an object using by first calling the lfun remove() of the
+ object and if its still "alive" then destruct it with the efun
+ destruct().
+
diff --git a/obj/tools/MGtool/man.d/xdlook b/obj/tools/MGtool/man.d/xdlook
new file mode 100644
index 0000000..6f7772f
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xdlook
@@ -0,0 +1,6 @@
+SYNOPSIS
+ xdlook <object>
+
+DESCRIPTION
+ Same as look, but takes a deep look at the object.
+
diff --git a/obj/tools/MGtool/man.d/xdo b/obj/tools/MGtool/man.d/xdo
new file mode 100644
index 0000000..cefa5f1
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xdo
@@ -0,0 +1,14 @@
+SYNOPSIS
+ xdo [<number1>#]<command1>[;[<number2>#]<command2>] ...
+
+DESCRIPTION
+ Perform multiple command execution.
+
+ Examples:
+ xdo 5#smile (smile 5 times)
+
+ xdo l;i (look around in the room and then in your inventory)
+
+ xdo s;9#w;3#n;kill shaman;get sword from corpse;3#s;9#e;n;...
+ (you know this one :)
+
diff --git a/obj/tools/MGtool/man.d/xdupdate b/obj/tools/MGtool/man.d/xdupdate
new file mode 100644
index 0000000..b3752b9
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xdupdate
@@ -0,0 +1,8 @@
+SYNOPSIS
+ xdupdate <filename>
+
+DESCRIPTION
+ Update an object including all its inherited objects.
+
+EXAMPLE
+ xdupdate /std/player.c
diff --git a/obj/tools/MGtool/man.d/xeval b/obj/tools/MGtool/man.d/xeval
new file mode 100644
index 0000000..f532bdf
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xeval
@@ -0,0 +1,18 @@
+SYNOPSIS
+ xeval <expression>
+
+DESCRIPTION
+ Execute an LPC expression. Inside the <expression>, "me" and "here" are
+ predefined objects (guess for what :). Here we can also use the function
+ "get()" to find an object using the object access syntax. If the
+ Expression returns an object the variable "$result" will be set to this.
+ xeval includes a private ~/.xtool.h, if it exists, to support user
+ defined macros.
+
+
+EXAMPLES
+ Just do it!
+ xeval users()
+ xeval getuid(me)
+ xeval get("$me.xtool")
+
diff --git a/obj/tools/MGtool/man.d/xforall b/obj/tools/MGtool/man.d/xforall
new file mode 100644
index 0000000..17558f4
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xforall
@@ -0,0 +1,29 @@
+SYNOPSIS
+ xforall <filepattern> <command>
+
+DESCRIPTION
+ Execute <command> for all matching files. The <command> string can
+ contain replacment marks. Currently there are five of these marks:
+ - "!!" this mark stands for the full file name.
+ - "!e" stands for the extension of the file name.
+ - "!f" stands for the file name without extension and directory name.
+ - "!h" stands for the full directory name of the files.
+ - "!r" stands for the full file name without file extension.
+ - "!t" stands for the file name without the directory name.
+
+ If the full file name would be "/directory/file.ext" then
+ "!!" equals "/directory/file.ext"
+ "!e" equals "ext"
+ "!f" equals "file"
+ "!h" equals "/directory"
+ "!r" equals "/directory/file"
+ "!t" equals "file.ext"
+
+EXAMPLES
+ xforall ~/room/*.c xcall !r->reset();
+ Call the reset() function in all your rooms.
+
+ xforall ~/obj/* mv !! !h/oldobj/!f.!e.old
+ Move all files from your "obj" dir into the "obj/oldobj" dir and change
+ the extensions.
+
diff --git a/obj/tools/MGtool/man.d/xgoto b/obj/tools/MGtool/man.d/xgoto
new file mode 100644
index 0000000..df4ccba
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xgoto
@@ -0,0 +1,16 @@
+SYNOPSIS
+ xgoto [object]
+
+DESCRIPTION
+ Go inside <object>. Without an argument you will leave into your
+ workroom. If <object> is a living thing, goto it's environment
+ (never tested until now, when going to a living thing, inside
+ a living thing :)
+
+EXAMPLES
+ xgoto /room/shop
+ xgoto shop (both are the same, because if there is no shop in
+ the current directory, a "/room/" will be appended
+ to the argument)
+ xgoto public enemy (do this only when you are really bored)
+
diff --git a/obj/tools/MGtool/man.d/xgrep b/obj/tools/MGtool/man.d/xgrep
new file mode 100644
index 0000000..8914fcb
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xgrep
@@ -0,0 +1,25 @@
+SYNOPSIS
+ xgrep [-iv] <regexp> <filepattern>
+ or
+ xgrep [-iv] <regexp> (when reading from a pipe)
+
+DESCRIPTION
+ Search for the regular expression <regexp> in all files matching the
+ <filepattern>.
+ Works simular to the Unix command "grep". The reslut will be written
+ to <STDOUT> and may be piped into another command.
+
+OPTIONS
+ -v reverts the sense of <regexp>.
+
+ -i matches case-insensitive
+
+EXAMPLES
+ xgrep Deepthought /log/SHOUTS
+ This will search throught the shout log file for any line which has
+ the word "Deepthought" in it.
+
+ xgrep create\(\) *.c
+ This will search for all lines of all lpc code files in the current dir
+ which have the function "create()" defined.
+
diff --git a/obj/tools/MGtool/man.d/xhbeats b/obj/tools/MGtool/man.d/xhbeats
new file mode 100644
index 0000000..3a897f3
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xhbeats
@@ -0,0 +1,18 @@
+SYNOPSIS
+ xhbeats [search pattern]
+ or
+ xhbeats (when writing to a pipe)
+
+DESCRIPTION
+ With no argument it shows all your objects which have a running heart
+ beat. With a regexp as argument, all matching objects will be printed.
+ When writing to a pipe, all hearbeats will be printed and a search
+ pattern is not allowed.
+
+EXAMPLES
+ xhbeats obj Show all objects which have a running heart beat at the
+ object names with the string "obj" in it.
+ xhbeats . Show all callouts. Please don't do this if it isn't
+ really neccessary. It just costs time - and what do you
+ want to do with this information?
+
diff --git a/obj/tools/MGtool/man.d/xhead b/obj/tools/MGtool/man.d/xhead
new file mode 100644
index 0000000..5801055
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xhead
@@ -0,0 +1,11 @@
+SYNOPSIS
+ xhead <-#> <file>
+ or
+ xhead <-#> (when reading from a pipe)
+
+DESCRIPTION
+ xhead prints the first part of a given file; It reads from a pipe
+ if no file is given.
+
+EXAMPLES
+ xhead -10 workroom.c prints the first 10 lines of the file workroom.c.
diff --git a/obj/tools/MGtool/man.d/xhelp b/obj/tools/MGtool/man.d/xhelp
new file mode 100644
index 0000000..b0aa7d4
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xhelp
@@ -0,0 +1,6 @@
+SYNOPSIS
+ xhelp
+
+DESCRIPTION
+ Show the main help file.
+
diff --git a/obj/tools/MGtool/man.d/xids b/obj/tools/MGtool/man.d/xids
new file mode 100644
index 0000000..67ef761
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xids
@@ -0,0 +1,6 @@
+SYNOPSIS
+ xids <object>
+
+DESCRIPTION
+ Show the user id and the effective user id of the <object>.
+
diff --git a/obj/tools/MGtool/man.d/xinherit b/obj/tools/MGtool/man.d/xinherit
new file mode 100644
index 0000000..ef02f3e
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xinherit
@@ -0,0 +1,16 @@
+SYNOPSIS
+ xinherit <object> [function]
+
+DESCRIPTION
+ Show the inheritance tree of an object and if optional specified
+ display all occurencies of the function.
+ The inheritance tree is perhaps not the one you expect to see. In
+ fact its the one the gamedriver really uses. That means if for
+ example two object inherit each other or in any other case of recursion
+ it will not be shown. Or if an object A inherits object B and C
+ and object B also inherits object C, the object C will only displayed
+ once (because the gamedriver also inherits object once).
+
+EXAMPLE
+ xinherit $me
+
diff --git a/obj/tools/MGtool/man.d/xlag b/obj/tools/MGtool/man.d/xlag
new file mode 100644
index 0000000..fd28114
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xlag
@@ -0,0 +1,16 @@
+SYNOPSIS
+ xlag
+
+DESCRIPTION
+ xlag displays the current system LAG by comparing the actual
+ processed heartbeats with the initial heartbeat rate (1/2s).
+ Values will we displayed for the last minute, the last 15 minutes
+ and the last hour.
+
+EXAMPLE
+ Letzte 60 min: ####### (7.2%)
+ Letzte 15 min: ######## (8.3%)
+ Letzte Minute: ######### (9.4%)
+
+AVAILABILITY
+ xlag requires /players/kirk/obj/lag-o-daemon.c to be loaded.
diff --git a/obj/tools/MGtool/man.d/xload b/obj/tools/MGtool/man.d/xload
new file mode 100644
index 0000000..00db877
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xload
@@ -0,0 +1,15 @@
+SYNOPSIS
+ xload <filename>
+
+DESCRIPTION
+ Update and load the object specified by the filename. If you update
+ your current environment, all players will be moved silently into
+ "/std/void" and after successful updating and loading back into it.
+
+EXAMPLES
+ xload $here
+ Update and reload the current room (but without a trip into the void :).
+
+ xload obj/little_thing.c
+ Update and load it.
+
diff --git a/obj/tools/MGtool/man.d/xlook b/obj/tools/MGtool/man.d/xlook
new file mode 100644
index 0000000..259bc9e
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xlook
@@ -0,0 +1,7 @@
+SYNOPSIS
+ xlook [object]
+
+DESCRIPTION
+ Look at the object. If the argument is ommitted, look inside the
+ current room.
+
diff --git a/obj/tools/MGtool/man.d/xlpc b/obj/tools/MGtool/man.d/xlpc
new file mode 100644
index 0000000..8f471ed
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xlpc
@@ -0,0 +1,20 @@
+SYNOPSIS
+ xlpc <lpc code>
+
+DESCRIPTION
+ Execute pure LPC code. "me" and "here" are predefined objects. Also the
+ <properties.h> will be included. The function "get(string)" can be used
+ for accessing objects. If the execution returns an object the variable
+ "$result" will set to this object.
+
+EXAMPLES
+ xlpc int i;object *o;o=users();for(i=0;i<sizeof(o);i++)o[i]->
+ SetProp(P_FROG,1);
+ (Let all users be slimy frogs :)
+
+ xlpc int i;object *o;o=users();for(i=0;i<sizeof(o);i++)
+ o[i]->SetProp(P_TITLE,get("$me")->QueryProp(P_TITLE));
+ (Give all users your prefered title. Take a look of the use of get().)
+
+ Both commands must be written in one line of course!
+
diff --git a/obj/tools/MGtool/man.d/xman b/obj/tools/MGtool/man.d/xman
new file mode 100644
index 0000000..9b56ad1
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xman
@@ -0,0 +1,17 @@
+SYNOPSIS
+ xman <topic>
+
+DESCRIPTION
+ Searches in some special directories under /doc for the given topic
+ or command. If there are two equal topics in different directories
+ the one found first will be printed.
+
+EXAMPLES
+ xman xman
+ xman xforall
+ xman efun/destruct
+ xman w/destruct
+ xman move
+ xman thing
+ xman domains
+
diff --git a/obj/tools/MGtool/man.d/xmore b/obj/tools/MGtool/man.d/xmore
new file mode 100644
index 0000000..bcd9250
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xmore
@@ -0,0 +1,12 @@
+SYNOPSIS
+ xmore <filename> [start]
+
+DESCRIPTION
+ Prints out a file and if a starting line is given, then the printing
+ will start there. On ansi or vt100 terminals the status line will be
+ overstroked to give a harmonic view of the file.
+
+EXAMPLES
+ xmore ~/workroom.c
+ xmore $here (this will show the source of the current room)
+
diff --git a/obj/tools/MGtool/man.d/xmove b/obj/tools/MGtool/man.d/xmove
new file mode 100644
index 0000000..b4c0aec
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xmove
@@ -0,0 +1,13 @@
+SYNOPSIS
+ xmove <object> into <object>
+
+DESCRIPTION
+ Moves one object into another or give the reason why the move failed.
+
+EXAMPLES
+ xmove $clone into $me
+ If you cloned an object with xclone but the object couldn't be moved
+ then this can be used to get the reason for it.
+
+ xmove hyp into ^wurzel (this is a silent form of going to other players)
+
diff --git a/obj/tools/MGtool/man.d/xmsg b/obj/tools/MGtool/man.d/xmsg
new file mode 100644
index 0000000..175b780
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xmsg
@@ -0,0 +1,11 @@
+SYNOPSIS
+ xmsg [to <object>|all]
+
+DESCRIPTION
+ Send a message. If no arguments are given the message will be send into
+ the room. If second argument is "to" then send the message to the
+ specified <object>. If second argument is "all" then send the message to
+ all players in the mud.
+ This command can be used to send text via cut&paste to someone without
+ putting a "say", "tell" or "shout" infront of each line.
+
diff --git a/obj/tools/MGtool/man.d/xmtp b/obj/tools/MGtool/man.d/xmtp
new file mode 100644
index 0000000..9d74a9c
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xmtp
@@ -0,0 +1,24 @@
+SYNOPSIS
+ xmtp [options] <directory> <file>
+
+DESCRIPTION
+ Create a script file for transfering complete directories with mtp.
+ If your mtp needs extra arguments (except of the -r option which
+ stands for reading files) for example the -g option then you can add
+ then to the command.
+ This command works recursively and can cause a to deep recursion or
+ a too long evaluation error when trying to make a script for huge
+ directories like "/players" for example.
+ If the <file> allready exists it will not be removed instead the script
+ will simply added to the end of the file.
+
+EXAMPLE
+ xmtp -gtubmud /basic ~/basic.csh
+ Create a script file "basic.csh" to transfer the whole content of the
+ "/basic" directory.
+
+ On your host you then just create a directory (normally with the same
+ name give to the xmtp command), change into the directory and read
+ the script file with "mtp -r basic.csh". Then just execute the script
+ with "csh" or "sh".
+
diff --git a/obj/tools/MGtool/man.d/xproc b/obj/tools/MGtool/man.d/xproc
new file mode 100644
index 0000000..16d0aa1
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xproc
@@ -0,0 +1,13 @@
+SYNOPSIS
+ xproc [-c] [-l] [-m] [-u] [-v]
+
+DESCRIPTION
+ xproc prints information from the /proc filesystem to the screen.
+ The format is totally unformatted! (I can't help it for now...)
+ Without any option, it display the machines load averages.
+
+ -c: cpu information
+ -l: load averages
+ -m: memory usage
+ -u: machine's uptime
+ -v: kernel version
diff --git a/obj/tools/MGtool/man.d/xprops b/obj/tools/MGtool/man.d/xprops
new file mode 100644
index 0000000..f8f0dfe
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xprops
@@ -0,0 +1,15 @@
+SYNOPSIS
+ xprops [-f|-m] <object>
+
+DESCRIPTION
+ Prints out all properties of <object> which are currently defined
+ in /sys/properties.h.
+
+OPTIONS
+ -f List property flags verbose
+
+ -m List property methods
+
+EXAMPLE
+ xprops $me
+
diff --git a/obj/tools/MGtool/man.d/xscan b/obj/tools/MGtool/man.d/xscan
new file mode 100644
index 0000000..7f7b450
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xscan
@@ -0,0 +1,7 @@
+SYNOPSIS
+ xscan
+
+DESCRIPTION
+ Scan current room for netdead players and check variables.
+ (There will follow more checking routines like snoop, invis etc. :)
+
diff --git a/obj/tools/MGtool/man.d/xset b/obj/tools/MGtool/man.d/xset
new file mode 100644
index 0000000..cb7c66d
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xset
@@ -0,0 +1,15 @@
+SYNOPSIS
+ xset [$<name>=<object>]
+
+DESCRIPTION
+ Without an argument all current variable settings will be shown and
+ destructed objects removed from the list of variables.
+ With argument the specified variable will be set.
+
+EXAMPLES
+ xset $deep=deepthought
+ xset $xtool=$me.xtool
+ xset $god=$deep
+ xset $last_result=$result
+ xset $3=^$1.3
+
diff --git a/obj/tools/MGtool/man.d/xsh b/obj/tools/MGtool/man.d/xsh
new file mode 100644
index 0000000..1377992
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xsh
@@ -0,0 +1,12 @@
+SYNOPSIS
+ xsh <filename>
+
+DESCRIPTION
+ Read in a file and execute each line of it as a command given from the
+ keyboard.
+
+EXAMPLE
+ xsh ~/setup.xsh
+ Execute the file "~/setup.xsh". This way you can set up your aliases or
+ other parameters for other tools if the setting gone lost.
+
diff --git a/obj/tools/MGtool/man.d/xsort b/obj/tools/MGtool/man.d/xsort
new file mode 100644
index 0000000..dfea2da
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xsort
@@ -0,0 +1,11 @@
+SYNOPSIS
+ xsort [-r] <file>
+ or
+ xsort [-r] (when reading from a pipe)
+
+DESCRIPTION
+ xsort sort all lines of a given file in increasing/decreasing order.
+ If no file is given it reads from a pipe.
+
+EXAMPLES
+ xsort -r workroom.c sorts all lines of workroom.c in reverse order.
diff --git a/obj/tools/MGtool/man.d/xtail b/obj/tools/MGtool/man.d/xtail
new file mode 100644
index 0000000..44c2300
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xtail
@@ -0,0 +1,12 @@
+SYNOPSIS
+ xtail <-|+#> <file>
+ or
+ xtail <-|+#> (when reading from a pipe)
+
+DESCRIPTION
+ xtail prints the last part of a given file; It reads from a pipe
+ if no file is given.
+
+EXAMPLES
+ xtail -10 workroom.c prints the last 10 lines of the file workroom.c.
+ xtail +10 workroom.c prints all lines of workroom.c beginning at line 10.
diff --git a/obj/tools/MGtool/man.d/xtool b/obj/tools/MGtool/man.d/xtool
new file mode 100644
index 0000000..62d0614
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xtool
@@ -0,0 +1,45 @@
+SYNOPSIS
+ xtool [update|heart=<on|off>|first=<on|off>|protect=<on|off>|
+ invcheck=<on|off>|envcheck=<on|off>|ndcheck=<on|off>|
+ varcheck=<on|off>|short=<on|off>|echo=<on|off>|
+ more=<amount>|kill|news|save|load|reset]
+
+DESCRIPTION
+ This command is used to set some tool-specific behaviours.
+ - "update" clones a new Xtool and destructs the old one. This should
+ only be done when working on the source of the tool and to get a fast
+ update. Settings and aliases will be reached through the new clone.
+ - "heart=<on|off>" turns the heart beat of the tool on or off.
+ The heart beat is for a higher security and to keep the other checks
+ running. If you just want to use the Xtool as a passive tool without
+ any checks then turn the heart beat off.
+ - "first=<on|off>" turns the automatic moving into the pole position
+ of your inventory on or off. Turning it off, avoids struggle with
+ other tools which behave same, but also reduces security. The history
+ mechanism will also capture the less commands.
+ - "protect=<on|off>" turns on/off the protection mode of the Xtool.
+ It will protect you from forces of other wizards and of player objects
+ which try to move into your inventory.
+ - "invcheck=<on|off>" turns the automatic check of your inventory on or
+ off. If turned on, all new objects in your inventory will be reported.
+ - "envcheck=<on|off>" like "invcheck" but checks your environment, the
+ content of the current room.
+ - "ndcheck=<on|off>" sets the netdeadchecking mode of the Xtool.
+ - "short=<on|off>" turns displaying of short descriptions on or off.
+ This is to avoid to get on other wizards nerves, when they have a tool
+ that notifies inventory checks (like this tool does :). But the main
+ reason is to cope with bad short descriptions of objects. For
+ example if you want to destruct it a bug in the short desc. would
+ make it nearly impossible to do so.
+ - "more=<amount>" sets the amount of lines that will be displayed at one
+ time with the xmore command. Will be removed soon because there is a
+ player property called P_PAGESIZE to take care of it.
+ - "echo=<on|off>" turns the echoing of commands executed via alias,
+ history or multiple command execution on or off.
+ - "kill" destructs the Xtool and removes it from the autoload list.
+ - "news" show the news and changes of the Xtool.
+ - "save" saves the settings of the Xtool including the aliases into a
+ file.
+ - "load" restores the saved settings from the save file.
+ - "reset" resets the Xtool.
+
diff --git a/obj/tools/MGtool/man.d/xtrace b/obj/tools/MGtool/man.d/xtrace
new file mode 100644
index 0000000..1c05e94
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xtrace
@@ -0,0 +1,14 @@
+SYNOPSIS
+ xtrace <object>
+
+DESCRIPTION
+ Trace all function calls with arguments and their return values of
+ the specified object. Without any argument turns the tracing off again.
+
+EXAMPLE
+ xtrace $me.buggything
+ Lets debug an buggy object.
+
+ xtrace
+ Turn debugging off.
+
diff --git a/obj/tools/MGtool/man.d/xtrans b/obj/tools/MGtool/man.d/xtrans
new file mode 100644
index 0000000..e356d0a
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xtrans
@@ -0,0 +1,6 @@
+SYNOPSIS
+ xtrans <player>
+
+DESCRIPTION
+ Teleport <player> to you.
+
diff --git a/obj/tools/MGtool/man.d/xuclone b/obj/tools/MGtool/man.d/xuclone
new file mode 100644
index 0000000..341c825
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xuclone
@@ -0,0 +1,13 @@
+SYNOPSIS
+ xuclone <filename>
+
+DESCRIPTION
+ Updates & Clones an object. On error, the error log file will be
+ printed. Moves the object (if possible) into your inventory. If the
+ object has been cloned successfully, the variable "$clone" will be set,
+ to make sure we don't lose the object out of sight :)
+
+EXAMPLE
+ xuclone /std/thing
+ xcall $clone->SetShort("a BIG thing!");
+
diff --git a/obj/tools/MGtool/man.d/xupdate b/obj/tools/MGtool/man.d/xupdate
new file mode 100644
index 0000000..cab6567
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xupdate
@@ -0,0 +1,10 @@
+SYNOPSIS
+ xupdate <filename>
+
+DESCRIPTION
+ Update an object by first calling the lfun "remove()" of it and when
+ it still exists destruct it.
+
+EXAMPLE
+ xupdate obj/blub.c
+
diff --git a/obj/tools/MGtool/man.d/xwc b/obj/tools/MGtool/man.d/xwc
new file mode 100644
index 0000000..aa13147
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xwc
@@ -0,0 +1,22 @@
+SYNOPSIS
+ xwc [-clw] <file>
+ or
+ xwc [-clw] (when reading from a pipe)
+
+DESCRIPTION
+ xwc counts the number of bytes, whitespace-separated words, and new-
+ lines in a given file, or reading from a pipe. It prints one line
+ of counts, and if the file name was given as an argument, it prints
+ the filename following the counts. The counts are printed in the
+ order: lines, words, bytes.
+ By default, wc prints all three counts.
+
+OPTIONS:
+ -c print character count
+
+ -l print line count
+
+ -w print word count
+
+EXAMPLES
+
diff --git a/obj/tools/MGtool/man.d/xwho b/obj/tools/MGtool/man.d/xwho
new file mode 100644
index 0000000..1e9fbd6
--- /dev/null
+++ b/obj/tools/MGtool/man.d/xwho
@@ -0,0 +1,17 @@
+SYNOPSIS
+ xwho [mail|ip|race|guild|domain|stats|cmdavg]
+
+DESCRIPTION
+ Without any argument this command behaves like the normal people
+ command. With the argument "mail" it will list all players with their
+ email address. With the argument "ip" it will list all players with
+ their host name and ip number. If the argument is "race" or "guild"
+ you will get a list of all players with these attributes. "domain"
+ will show the domain(s) of the current players. And with "stats" it
+ will print some stats information of all players.
+ The argument "cmdavg" list the value of _query_command_average()
+ for every user sorted in increasing order.
+
+EXAMPLES
+ xwho
+ xwho ip
diff --git a/obj/tools/MGtool/proc/cpuinfo b/obj/tools/MGtool/proc/cpuinfo
new file mode 120000
index 0000000..4ae7d7e
--- /dev/null
+++ b/obj/tools/MGtool/proc/cpuinfo
@@ -0,0 +1 @@
+/proc/cpuinfo
\ No newline at end of file
diff --git a/obj/tools/MGtool/proc/loadavg b/obj/tools/MGtool/proc/loadavg
new file mode 120000
index 0000000..e6983f4
--- /dev/null
+++ b/obj/tools/MGtool/proc/loadavg
@@ -0,0 +1 @@
+/proc/loadavg
\ No newline at end of file
diff --git a/obj/tools/MGtool/proc/meminfo b/obj/tools/MGtool/proc/meminfo
new file mode 120000
index 0000000..338b570
--- /dev/null
+++ b/obj/tools/MGtool/proc/meminfo
@@ -0,0 +1 @@
+/proc/meminfo
\ No newline at end of file
diff --git a/obj/tools/MGtool/proc/uptime b/obj/tools/MGtool/proc/uptime
new file mode 120000
index 0000000..2772a8f
--- /dev/null
+++ b/obj/tools/MGtool/proc/uptime
@@ -0,0 +1 @@
+/proc/uptime
\ No newline at end of file
diff --git a/obj/tools/MGtool/proc/version b/obj/tools/MGtool/proc/version
new file mode 120000
index 0000000..b17af1e
--- /dev/null
+++ b/obj/tools/MGtool/proc/version
@@ -0,0 +1 @@
+/proc/version
\ No newline at end of file
diff --git a/obj/tools/MGtool/prof.h b/obj/tools/MGtool/prof.h
new file mode 100644
index 0000000..05dcebf
--- /dev/null
+++ b/obj/tools/MGtool/prof.h
@@ -0,0 +1,42 @@
+private mixed __tm__=({0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0});
+private mixed __xtm__=({0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0});
+private mixed __ec__=({0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0});
+private mixed __xec__=({0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0});
+private int __level__;
+private mapping __data__ = ([]);
+__query_xprof_data__() { return __data__; }
+#define U2T(ru) (((ru)[0]+(ru)[1])*10)
+#define EC1 40
+#define EC2 22
+#define EC3 150
+#define TM1 0
+#define TM2 0
+#define TM3 0
+#define F(func,name,args) func args { \
+ mixed *__dt__, *__ru__, __re__; \
+ int __t__; \
+ if(!__data__) return :: func args; \
+ __ru__=rusage(); \
+ __tm__[__level__]=(__t__=U2T(__ru__))<0?0:__t__; \
+ __xtm__[__level__]=TM1; __tm__[__level__+1]=0; \
+ __ec__[__level__]=get_eval_cost(); \
+ __xec__[__level__]=EC1; __ec__[__level__+1]=0; \
+ __level__++; __re__ = :: func args; __level__--; \
+ if(!(__dt__=__data__[name])) { \
+ __dt__=__data__[name]=({0,0,0,0,0}); \
+ __xtm__[__level__]+=TM2; __xec__[__level__]+=EC2; \
+ } \
+ __ec__[__level__]-=get_eval_cost()+__xec__[__level__]; \
+ __ru__=rusage(); \
+ __t__=(__t__=U2T(__ru__))<0?0:__t__; \
+ __tm__[__level__]=__t__-__tm__[__level__]-__xtm__[__level__]; \
+ __dt__[0]++; \
+ __dt__[1]+=__ec__[__level__]-__ec__[__level__+1]; \
+ __dt__[2]+=__tm__[__level__]-__tm__[__level__+1]; \
+ __dt__[3]+=__ec__[__level__]; __dt__[4]+=__tm__[__level__]; \
+ if(__level__>0) { \
+ __xec__[__level__-1]+=__xec__[__level__]+EC3; \
+ __xtm__[__level__-1]+=__xtm__[__level__]+TM3; \
+ } \
+ return __re__; \
+}
diff --git a/obj/tools/MGtool/tool.doc b/obj/tools/MGtool/tool.doc
new file mode 100644
index 0000000..df477ce
--- /dev/null
+++ b/obj/tools/MGtool/tool.doc
@@ -0,0 +1,101 @@
+COMMANDS:
+ xcall xddes xforall xids xman xscan xtrace
+ xcallouts xdes xgoto xinherit xmore xset xtrans
+ xclean xdlook xgrep xlag xmove xsh xuclone
+ xclone xdo xhbeats xload xmsg xsort xupdate
+ xdbg xdupdate xhead xlook xmtp xtail xwc
+ xdclean xeval xhelp xlpc xprops xtool xwho
+
+
+Give a "?" as single argument to get the command usage or do "xman <command>"
+for more information about a command.
+
+QUICKTYPER:
+ The MGtool contains a full quicktyping tool. It provides the following
+ features:
+
+ - multiple command execution (see the xdo and xforall command)
+ - script files (see the xsh command)
+ - command pipelining
+ - command history
+
+ The command history stores (nearly) each command you type in and lets you
+ re-execute it.
+
+ - %! show the command history
+ - %% re-execute the last command
+ - ^old^new re-execute the last command but replace all occurencies of
+ the "old" string of the command by "new".
+ - %num re-execute the command at position num of the history
+ - %str re-execute the last command beginning with the string "str"
+
+
+COMMAND ARGUMENTS:
+ Most commands need filenames or objects as argument. The way objects are
+ specified will be descriped in the following.
+
+ - an object can be accessed directly by its unique object name
+ - a player can be accessed by its player name
+ - a living can be accessed by its living name
+ - a object inside the current room by its id
+ - a object inside the current room by its position
+
+ If the object can not be accessed by the above mentioned ways you can also
+ use the following object modifiers:
+
+ ^obj stands for the environment of an object
+ obj1.obj2 stands for an object obj2 inside another object obj1
+
+ These modifiers can be concatenated together where the "^" has a higher
+ priority than the ".". This allows you to access an object from another know
+ object.
+
+ Now some examples which demonstrates how to use this accessing mechanism.
+ Therefore we use the command "xlook" which prints the short and long
+ description and also the content of an object:
+
+ 1. xlook deepthought
+ Look at Deepthought.
+ 2. xlook ^deepthought
+ Look at the room Deepthought is in.
+ 3. xlook deepthought.bag
+ Look at the bag of Deepthought.
+ 4. xlook deepthought.bag.bag
+ Look at the bag inside Deeps bag.
+ 4. xlook deepthought.5
+ Look at the fifth object of Deeps inventory.
+ 5. xlook /std/thing#123
+ Look at the object with the unique object name "/std/thing#123".
+ 6. xlook 1
+ Look at the first object in the current room.
+ 7. xlook 1.2.3
+ Look at the third of the second of the first object in the room.
+
+ If the name of an object contains an object modifier as a character then it
+ can be escaped by a "\". A "\" is escaped by itself. This is because file
+ names often contain the "." for file extensions. So if you want to access
+ directly an object with for example such a name "file.old.bulb" you have to
+ write "file\.old\.blub".
+
+ If a command needs a file as argument you can use the filename of an object
+ for it by placing an "@" infront of the object. This way you can clone
+ an object by using another clone:
+
+ xclone @harry.bag.candles
+ Clone some candles of the kind Harry is carrying in his bag.
+
+
+ARGUMENT VARIABLES:
+ Whenever an object or a filename is needed, we can use variables.
+ A variable allways starts with a "$" followed by the name which
+ identificates it. Two variable names are reserved for special purpose.
+ The first, "$me" is always set to the one who owns the Xtool. The other,
+ "$here" represents the current room.
+
+ (Instead of "$me" and "$here" you can also use "$m" and "$h".)
+
+ If a command needs a file as argument and gets a variable it will be
+ automatically converted into the source file of the object.
+ (This is done by taking the unique object identifier and replacing the
+ "#..." by a ".c".)
+
diff --git a/obj/tools/MGtool/tool.h b/obj/tools/MGtool/tool.h
new file mode 100644
index 0000000..1eff23d
--- /dev/null
+++ b/obj/tools/MGtool/tool.h
@@ -0,0 +1,246 @@
+#ifndef __TOOL_H__
+#define __TOOL_H__
+
+/*
+ * MGtool-1.3
+ * File: tool.h
+ * Maintainer: Kirk@MorgenGrauen
+ */
+
+/*------------------------------------------*/
+/* the original Xtool is copyrighted by Hyp */
+/*------------------------------------------*/
+
+#ifndef MASTER
+#define MASTER __MASTER_OBJECT__
+#endif
+
+#define VOID "/room/void"
+
+#define NULL (0)
+#define FALSE (0)
+#define TRUE (1)
+#define ERROR (-1)
+#define PREV previous_object()
+#define TP efun::this_player()
+#define RTP efun::this_interactive()
+#define TOOL_NAME "MGtool"
+#define TOOL_VERSION "1.3.3"
+#define TOOL_TITLE TOOL_NAME+" v"+TOOL_VERSION
+#define TOOL_INTERNAL "1.3.3-10.07.97"
+
+#define TOOL_PATH "/obj/tools/MGtool"
+
+#define TOOL_MANPAGE TOOL_PATH+"/tool.doc"
+#define TOOL_NEWS TOOL_PATH+"/tool.news"
+#define TOOL_LOG "/log/xtool"
+#define XPROF_MACRO TOOL_PATH+"/prof.h"
+#define LAG_O_DAEMON "/p/daemon/lag-o-daemon"
+
+#define TOOL_LEVEL (40)
+
+#define MORE_LINES (20)
+#define MAX_HISTORY (25)
+#define MAX_RECURSION (6)
+#define TRACE_LEVEL (1|2|4|8)
+#define AUTOLOAD_ARGS ({TOOL_INTERNAL, modi, morelines})
+#define EXEC_LINES (10)
+#define EXEC_TIME (1)
+
+#define IA(x) interactive(x)
+#define ENV(x) environment(x)
+#define LOWER(x) lower_case(x)
+#define NAME(x) ((string)x->query_name())
+#define CNAME(x) CAP((string)NAME(x))
+
+#define RNAME(x) getuid(x)
+#define CRNAME(x) CAP(RNAME(x))
+
+#define LEVEL(x) query_wiz_level(x)
+
+#define FORALL(x, y) for(x=first_inventory(y);x;x=next_inventory(x))
+#define DESTRUCT(x) Destruct(x)
+#define ALEFT(x,y,z) sprintf("%-*'"+z+"'s", y, (""+(x))[0..y-1])
+#define ARIGHT(x,y,z) sprintf("%*'"+z+"'s" , y, (""+(x))[0..y-1])
+#define W(x) Write(x)
+#define WLN(x) W(x+"\n")
+#define WDLN(x) W(x+".\n")
+
+#define MODE_ON(x) (modi|=x)
+#define MODE_OFF(x) (modi&=~x)
+#define MODE(x) (modi&x)
+#define MODE_HEART (1)
+#define MODE_FIRST (2)
+#define MODE_PROTECT (4)
+#define MODE_INVCHECK (8)
+#define MODE_ENVCHECK (16)
+#define MODE_NDCHECK (32)
+#define MODE_VARCHECK (64)
+#define MODE_ECHO (128)
+#define MODE_SHORT (256)
+#define MODE_SNOOPCHK (512)
+#define MODE_INVISCHK (1024)
+#define MODE_SCANCHK (2048)
+
+#define ERR_FILE "/players/"+RNAME(cloner)+"/.err"
+#define LPC_FILE "/players/"+RNAME(cloner)+"/.tool.lpc"
+#define TMP_FILE "/players/"+RNAME(cloner)+"/.tool.tmp"
+#define SAVE_FILE "/players/"+RNAME(cloner)+"/.toolrc"
+#define XPROF_FILE "/players/"+RNAME(cloner)+"/prof.c"
+#define PIPE_FILE "/players/"+RNAME(cloner)+"/.tool.pipe"
+#define PRIVATE_HEADER "/players/"+RNAME(cloner)+"/.xtool.h"
+#define PIPE_DELETE(x) if(pipe_out&&pipe_ovr&&file_size(x)>=0) rm(x)
+
+#define PIPE_IN 1
+#define PIPE_OUT 2
+#define PIPE_MAX 10000
+
+#define XGREP_REVERT 1
+#define XGREP_ICASE 2
+
+#define SECURE1() if(!security()) return;
+#define SECURE2(x) if(!security()) return x;
+#define USAGE1(x,y) notify_fail("Usage: "+(y)+"\n");\
+ if((x)=="?") return FALSE;
+#define USAGE2(x,y) notify_fail("Usage: "+(y)+"\n");\
+ if((!(x))||((x)=="?")) return FALSE;
+#define USAGE3(x) return WLN("Usage: "+(x))
+
+static int CatFile();
+static int Command(string str);
+int CommandScan(string arg);
+int DoAlias(string verb, string arg);
+int DoHistory(string line);
+static int MoveObj(object obj1, object obj2, int silent);
+static int XGrepFile(string pat, string file, int revert);
+int Xcall(string str);
+int Xcallouts(string str);
+int Xcat(string str);
+int Xcindent(string str);
+int Xclean(string str);
+int Xclone(string str);
+int Xuclone(string str);
+int Xcmds(string str);
+int Xdate(string str);
+int Xdbg(string str);
+int Xdclean(string str);
+int Xddes(string str);
+int Xdes(string str);
+int Xdlook(string str);
+int Xdo(string str);
+int Xdupdate(string str);
+int Xecho(string str);
+int Xeval(string str);
+int Xforall(string str);
+int Xgoto(string str);
+int Xgrep(string str);
+int Xhbeats(string str);
+int Xhead(string str);
+int Xhelp(string str);
+int Xids(string str);
+int Xinfo(string str);
+int Xinherit(string str);
+int Xinventory(string str);
+int Xlag(string str);
+int Xlight(string str);
+int Xload(string str);
+int Xlook(string str);
+int Xlpc(string str);
+int Xman(string str);
+int Xmore(string str);
+int Xmove(string str);
+int Xmsg(string str);
+int Xmtp(string str);
+int Xproc(string str);
+int Xprops(string str);
+int Xprof(string str);
+int Xquit(string str);
+int Xscan(string str);
+int Xset(string str);
+int Xsh(string str);
+int Xsort(string str);
+int Xstop(string str);
+int Xtool(string str);
+int Xtrace(string str);
+int Xtrans(string str);
+int Xupdate(string str);
+int Xwc(string str);
+int Xwho(string opt);
+static string crname(object who);
+int id(string str);
+int move(mixed dest);
+static int security();
+int write_newinvobj(object who);
+int write_newenvobj(object who);
+int write_netdead(object who);
+int write_alive(object who);
+int write_snoopee(object who);
+int write_nosnoop(object who);
+int write_invisobj(object who);
+int write_invislvg(object who);
+int write_invisply(object who);
+int write_visibobj(object who);
+int write_visiblvg(object who);
+int write_visibply(object who);
+static object *SubNodes(object obj);
+static varargs object FindObj(string str, object env, int silent);
+static object VarToObj(string str);
+static varargs object XFindObj(string str, int silent);
+static string ObjFile(object obj);
+static string PlayerAge(object obj);
+static string PlayerDomain(object obj, int flag);
+static string PlayerIP(object obj, int flag);
+static string PlayerIdle(object obj);
+static string PlayerMail(object obj, int flag);
+static string PlayerRace(object obj, int flag);
+static string PlayerSnoop(object obj, int flag);
+static string PlayerStats(object obj, int flag);
+static string PlayerWho(object obj);
+static string VarToFile(string str);
+static string VarToPureFile(string str);
+static string XFile(string file);
+static string XFindFile(string file);
+static varargs void DeepPrintShort(object env, int indent, string pre, string file);
+static void Destruct(object obj);
+static void DumpProperties(object obj, int flag);
+static void Inheritance(object obj, string func, string pre);
+void InvisCheck();
+static void MoreFile(string str);
+void NetDeadCheck(int show);
+static void PrintObj(object obj, string file);
+static varargs void PrintShort(string pre, object obj, string file);
+void SnoopCheck();
+static void VarCheck(int show);
+static int Write(string str);
+static void XExecFile(int line);
+static void XMoreFile(string file, int flag);
+static void XMsgSay(string str);
+static void XMsgShout(string str);
+static void XMsgTell(string str);
+static void XmtpScript(string dir, string file, string opt);
+void actions();
+void init();
+void update_tool(mixed *args, object obj);
+string _query_long();
+string _query_short();
+
+static int CallFunc(string verb, string str);
+static string GetFunc(string verb, int test);
+
+static string PrepareLine(string str);
+static string QuoteLine(string str);
+static string UnquoteLine(string str);
+int QuoteOk(string str);
+static string *ExplodeCmds(string str);
+
+string read_buffer(string filename, int start, int number);
+string load_buffer(int line);
+int read_line(int offset);
+
+/*
+ * debug stuff
+ */
+void TK(string str);
+int Xtk(string str);
+
+#endif /* __TOOL_H__ */
diff --git a/obj/tools/MGtool/tool.news b/obj/tools/MGtool/tool.news
new file mode 100644
index 0000000..92adbd9
--- /dev/null
+++ b/obj/tools/MGtool/tool.news
@@ -0,0 +1,143 @@
+[10.07.97]
+
+- fixed minor bug in command lookup:
+ 'xdosomethingorsomethingelse' was previously executed as 'xdo'
+ This is treated as an unknown command now. Anyway commands may be
+ abbreviated as long as they are not ambiguous.
+
+[12.03.97]
+
+- xlpc includes some more std-include-files and .xtool.h (if present)
+
+[04.03.97]
+
+- new command: xproc
+ display some information from the /proc filesystem in a very raw fashion.
+
+[08.05.96]
+
+- Xmore/Xtail: modified MoreFile/CatFile using new read_buffer() instead of
+ read_file() function which is VERY slow when giving offsets as argument.
+
+[13.02.96]
+
+- see below ...
+
+[03.01.96]
+
+- new command line parser under development (ALPHA!)
+
+[21.11.95]
+
+- MGtool will be destructed during creation, when !IS_LEARNER(<cloner>) is true
+
+- new option "-s" to xi[nventory] prints short inventory list (filenames only).
+ This is useful for alert object "... scanned your inventory" etc.
+ xi accepts <username> as optional argument to retrieve <username>'s
+ inventory instead of the cloner's own inventory and may write into pipes
+ to create command chains like: xi -s kirk|xgrep MGtool
+
+- new command xlag :-)
+
+[09.11.95]
+
+- bugfix: xinherit now calls xinherit and NOT xinventory
+
+[23.08.95]
+
+- xcall and xeval try to include a private header file ~/.xtool.h if one
+ exists. You may define own macros or whatever to make things easier
+
+[21.06.95]
+
+- new option "cmdavg" to xwho, shows command_average in ascending order
+
+[20.06.95]
+
+- removed redirecting of xcall and xeval (too buggy)
+
+- added options -f and -m to xprops (show propflags and propmethods)
+
+[06.06.95]
+
+ ** IMPORTANT ** (not backward compatible change)
+- xcall and xeval now write to a file, when redirecting their output
+ using '>'. It is also possible to pipe output into other commands
+
+[30.05.95]
+
+- xlook/xdlook are now able to write into pipes
+
+- xwho shows the name of any user currently logging in
+ instead of simply " R O O T "
+
+[10.04.95]
+
+- added option -i to xgrep (ignore case)
+
+- bugfix in command pipelines
+
+[28.03.95]
+
+- xinherit is now able to write into pipes
+
+[20.03.95]
+
+- added IO redirection like: xwho ip > testfile or xwho >> testfile
+ and: xmore < testfile
+ (this is very ALPHA!!!)
+
+[01.03.95]
+
+- new command xwc. Count lines, words and chars in file
+ Syntax xwc [-clw] [file] (is able to read from pipe)
+
+[17.02.95]
+
+- changed formatting of xprops output
+
+[15.02.95]
+
+- lots of code added, some rewritten
+
+- removed xalias capability (the shell alias provides the same functionality)
+
+- removed xcindent, xdate, xquit
+
+- bugs fixed in xcallouts, xprops, xman (when using xxtool)
+
+- added command pipelines for selected commands:
+
+ -> cmd : is able to read from pipe
+ cmd -> : is able to write into pipe
+
+ xcallouts ->
+ -> xcat ->
+ xcmds ->
+ -> xgrep ->
+ xhbeats ->
+ -> xhead ->
+ -> xmore
+ -> xmsg
+ xprops ->
+ -> xsort ->
+ -> xtail ->
+ xwho ->
+
+ the general syntax using pipes is:
+
+ cmd_a [arg_a] | cmd_b [arg_b] | ...
+
+ only the first space between cmd_a and arg_a or between cmd_a and the
+ first pipe symbol is necessary.
+
+ All functions which allow direct output into a pipe don't use a pager
+ to show its output even if no pipe follows this command. You may use
+ cmd [arg]|xmore to obtain the old results.
+
+- new commands xtail, xhead, xcat and xsort
+
+- command line option -v added to xgrep to print lines not matching the search
+ pattern
+
+- i/o redirection is coming soon
diff --git a/obj/tools/MGtool/toolcmd.c b/obj/tools/MGtool/toolcmd.c
new file mode 100644
index 0000000..83504b4
--- /dev/null
+++ b/obj/tools/MGtool/toolcmd.c
@@ -0,0 +1,2033 @@
+/*
+ * MGtool-1.0
+ * File: toolcmds.c
+ * Maintainer: Kirk@MorgenGrauen
+ */
+
+/*------------------------------------------*/
+/* the original Xtool is copyrighted by Hyp */
+/*------------------------------------------*/
+
+#include "tool.h"
+
+/*----------------------------------------------------------------------
+ * command functions
+ */
+
+int Xcall(string str)
+{
+ object obj, callobj;
+ string file, callstr, callfun, callexpr, error, errlog;
+ int *ru1, *ru2, xtime;
+ mixed res;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xcall <object>-><function>(<arguments>)");
+ TK("Xcall: str: "+(str?str:"(NULL)"));
+ if(sscanf(str, "%s->%s(%s", callstr, callfun, callexpr)!=3)
+ return FALSE;
+ if(!(callobj=XFindObj(callstr)))
+ return TRUE;
+ else
+ {
+#if 0
+ write_file(TOOL_LOG,
+ sprintf("%s (%s) xcall %s (env: %s)\n",ctime(time()),
+ getuid(cloner),str,object_name(environment(cloner))));
+#endif
+ file=LPC_FILE+".c";
+ if(file_size(file)>0)
+ rm(file);
+ if(obj=find_object(LPC_FILE))
+ Destruct(obj);
+ obj=0;
+ write_file(file,
+ "#include <properties.h>\n"+
+ "#include <thing/properties.h>\n"+
+ "#include <defines.h>\n"+
+ "#include <wizlist.h>\n"+
+ "#include <moving.h>\n"+
+ "#include \"/secure/wizlevels.h\"\n"+
+ (file_size(PRIVATE_HEADER)>=0?"#include \""+PRIVATE_HEADER+"\"\n":"")+
+ "mixed get(string str){return previous_object()->XFindObj(str);}\n"+
+ "mixed eval(object obj,mixed me,mixed here){return obj->"+callfun+"("+callexpr+";}\n");
+ errlog = ERR_FILE;
+ if(file_size(errlog)>0)
+ rm(errlog);
+ if(error=catch((LPC_FILE)->__nixgibts__()))
+ W("Error: "+error[1..]);
+ else
+ {
+ obj=find_object(LPC_FILE);
+ ru1=rusage();
+ error=catch(res=(mixed)obj->eval(callobj, cloner, ENV(cloner)));
+ ru2=rusage();
+ if(error)
+ W("Error: "+error[1..]);
+ else
+ {
+ xtime=ru2[0]-ru1[0]+ru2[1]-ru1[1];
+ WDLN("Evaluation time: "+(xtime<0 ? 0 : xtime)+" ms");
+ PIPE_DELETE(pipe_of);
+ if(pipe_out&&pipe_of)
+ write_file(pipe_of,mixed_to_string(res, MAX_RECURSION)+"\n");
+ else
+ WLN("Result: "+mixed_to_string(res, MAX_RECURSION));
+ if(objectp(res))
+ m_add(variable, "result", res);
+ }
+ }
+ rm(file);
+ }
+ if(obj) Destruct(obj);
+ return TRUE;
+}
+
+int Xcallouts(string str)
+{
+ object obj;
+ mixed callouts, args;
+ string fun, tmp, file;
+ int delay, i, s;
+
+ SECURE2(TRUE);
+ TK("Xcallouts: str: "+(str?str:"(NULL)"));
+ if(!pipe_out)
+ {
+ USAGE1(str, "xcallo(uts) [search pattern]");
+ file=TMP_FILE;
+ if(file_size(file)>0)
+ rm(file);
+ if(!str)
+ str="^\\[~/";
+ else if(!regexp(({"dummy"}), str))
+ {
+ WDLN("Bad regular expression");
+ return TRUE;
+ }
+ }
+ else
+ {
+ USAGE1(str, "xcallo(uts)");
+ if(str&&str!="")
+ {
+ WDLN("More arguments than expected");
+ return TRUE;
+ }
+ }
+ callouts=call_out_info();
+ s=sizeof(callouts);
+ PIPE_DELETE(pipe_of);
+ for(i=0; i<s; i++)
+ {
+ if(callouts[i]&&pointerp(callouts[i]))
+ {
+ tmp=sprintf("%O %Os %O (%s)",callouts[i][0],callouts[i][2],
+ callouts[i][1],(sizeof(callouts[i])>3?
+ mixed_to_string(callouts[i][3],
+ MAX_RECURSION):"0"));
+ if(pipe_out&&pipe_of)
+ write_file(pipe_of,tmp+"\n");
+ else
+ if(sizeof(regexp(({tmp}), str)))
+ WLN(tmp);
+ }
+ }
+ return TRUE;
+}
+
+int Xcat(string str)
+{
+ string *tmp,file;
+ int s;
+
+ SECURE2(TRUE);
+ TK("Xcat: str: "+str);
+ if(!pipe_in)
+ {
+ USAGE2(str, "xcat <file>");
+ if(!(file=XFindFile(str)))
+ {
+ WDLN("Can't find file");
+ return TRUE;
+ }
+ }
+ else
+ {
+ if(str&&str!="-")
+ USAGE3("xcat -");
+
+ if (file_size(file=pipe_if)<0)
+ {
+ WDLN("Missing input to xcat");
+ return TRUE;
+ }
+ }
+ tmp=old_explode(read_file(file,0,PIPE_MAX),"\n");
+ if(pipe_in&&pipe_if==PIPE_FILE)
+ rm(PIPE_FILE);
+ if (pipe_out&&pipe_of)
+ write_file(pipe_of,implode(tmp,"\n")+"\n");
+ else
+ WLN(implode(tmp,"\n"));
+ return TRUE;
+}
+
+int Xcd(string str)
+{
+ object dest;
+ string path;
+
+ SECURE2(TRUE);
+ USAGE1(str, "xcd [object]");
+ TK("Xcd: str: "+(str?str:"(NULL)"));
+ if(!str)
+ {
+ if(!(path=(string)cloner->QueryProp("start_home")))
+ path="/";
+ }
+ else if((dest=XFindObj(str,1)))
+ path="/"+implode(old_explode(object_name(dest),"/")[0..<2],"/");
+ else
+ path="";
+
+ TK("Xcd: path: "+(path?path:"(NULL)"));
+ if(!sizeof(path))
+ path=str;
+ PL->_cd(path);
+
+ return TRUE;
+}
+
+int Xclean(string str)
+{
+ object env;
+
+ SECURE2(TRUE);
+ USAGE1(str, "xcle(an) [object]");
+ TK("Xclean: str: "+(str?str:"(NULL)"));
+ if(!str)
+ env=ENV(cloner);
+ if(env||(env=XFindObj(str)))
+ {
+ PrintShort("Cleaning: ", env);
+ filter(filter(all_inventory(env), #'is_not_player),//'
+ "Destruct", ME);
+ }
+ return TRUE;
+}
+
+int Xclone(string str)
+{
+ object obj;
+ string file, errlog, error;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xclo(ne) <filename>");
+ if(!(file=XFindFile(str))) return TRUE;
+ errlog=ERR_FILE;
+ if(file_size(errlog)>0) rm(errlog);
+ WLN("Clone: "+short_path(file));
+ if(!(error=catch(obj=clone_object(file))))
+ {
+ m_add(variable, "clone", obj);
+ if(!MoveObj(obj, ENV(cloner), TRUE))
+ WDLN("Cannot move object into this room");
+ else if(!obj->QueryNoGet())
+ {
+ if(!MoveObj(obj, cloner, TRUE))
+ WDLN("Cannot move object into your inventory");
+ }
+ }
+ else
+ W("Error: "+error[1..]);
+ return TRUE;
+}
+
+int Xuclone(string str)
+{
+ object obj;
+ string file, errlog, error;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xuclo(ne) <filename>");
+ if(!(file=XFindFile(str))) return TRUE;
+ errlog=ERR_FILE;
+ if(file_size(errlog)>0) rm(errlog);
+ if(obj=find_object(file)) {
+ Destruct(obj);
+ WLN("Update and clone: "+short_path(file));
+ }
+ else
+ WLN("Clone: "+short_path(file));
+ if(!(error=catch(obj=clone_object(file))))
+ {
+ variable["clone"] = obj;
+ if(!MoveObj(obj, ENV(cloner), TRUE))
+ WDLN("Cannot move object into this room");
+ else if(!obj->QueryNoGet())
+ {
+ if(!MoveObj(obj, cloner, TRUE))
+ WDLN("Cannot move object into your inventory");
+ }
+ }
+ else
+ W("Error: "+error[1..]);
+ return TRUE;
+}
+
+int Xcmds(string str)
+{
+ object obj;
+ mixed *cmds;
+ int i, s;
+
+ SECURE2(TRUE);
+ USAGE1(str, "xcm(ds) [object]");
+ TK("Xcmds: str: "+(str?str:"(NULL)"));
+ if(!str)
+ obj=ENV(cloner);
+ else if(!(obj=XFindObj(str)))
+ {
+ WDLN("Can't find object");
+ return TRUE;
+ }
+ s=sizeof(cmds=query_actions(cloner,1|2|4|8|16));
+ PIPE_DELETE(pipe_of);
+ for(i=0; i<s; i+=5)
+ if(cmds[i+3]==obj)
+ if(pipe_out&&pipe_of)
+ write_file(pipe_of,ALEFT(cmds[i]+" ", 15, ".")+
+ (cmds[i+2] ? " * " : " . ")+cmds[i+4]+"()\n");
+ else
+ WLN(ALEFT(cmds[i]+" ", 15, ".")+
+ (cmds[i+2] ? " * " : " . ")+cmds[i+4]+"()");
+ return TRUE;
+}
+
+int Xdbg(string str)
+{
+ object obj;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xdb(g) <object>");
+ TK("Xdbg: str: "+(str?str:"(NULL)"));
+ if((obj=XFindObj(str)))
+ {
+ debug_info(1, obj);
+ debug_info(0, obj);
+ }
+ return TRUE;
+}
+
+int Xdclean(string str)
+{
+ object env;
+
+ SECURE2(TRUE);
+ USAGE1(str, "xdc(lean) [object]");
+ TK("Xdclean: str: "+(str?str:"(NULL)"));
+ if(!str)
+ env=ENV(cloner);
+ if(env||(env=XFindObj(str)))
+ {
+ PrintShort("Deep cleaning: ", env);
+ filter(filter(all_inventory(env), #'is_not_player, ME),//'
+ "DeepClean", ME);
+ }
+ return TRUE;
+}
+
+int Xddes(string str)
+{
+ object obj;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xdd(es) <object>");
+ TK("Xddes: str: "+(str?str:"(NULL)"));
+ if((obj=XFindObj(str)))
+ {
+ PrintShort("Deep destruct: ", obj);
+ filter(deep_inventory(obj), "Destruct", ME);
+ Destruct(obj);
+ }
+ return TRUE;
+}
+
+int Xdes(string str)
+{
+ object obj;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xde(s) <object>");
+ TK("Xdes: str: "+(str?str:"(NULL)"));
+ if((obj=XFindObj(str)))
+ {
+ PrintShort("Destruct: ",obj);
+ Destruct(obj);
+ }
+ return TRUE;
+}
+
+int Xdlook(string str)
+{
+ object obj;
+
+ SECURE2(TRUE);
+ USAGE1(str, "xdl(ook) [object]");
+ TK("Xdlook: str: "+(str?str:"(NULL)"));
+ if(!str)
+ obj=cloner;
+ if(obj||(obj=XFindObj(str)))
+ {
+ PIPE_DELETE(pipe_of);
+ DeepPrintShort(obj,NULL,NULL,(pipe_out&&pipe_of)?pipe_of:"");
+ }
+ return TRUE;
+}
+
+int Xdo(string str)
+{
+ int i, n, s;
+ string *strs, cmd;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xdo [<number1>#]<command1>[;[<number2>#]<command2>] ...");
+ if(!str||str==""||!(s=sizeof(strs=strip_explode(str, ";"))))
+ return FALSE;
+ for(i=0; i<s; i++)
+ {
+ if(strs[i])
+ {
+ switch(sscanf(strs[i], "%d#%s", n, cmd))
+ {
+ case 0:
+ if(!Command(strs[i])) return TRUE;
+ break;
+ case 1:
+ if(cmd&&(!Command(cmd))) return TRUE;
+ break;
+ case 2:
+ n= n<1 ? 1 : n;
+ if(cmd)
+ {
+ while(n--)
+ if(!Command(cmd)) return TRUE;
+ }
+ break;
+ }
+ }
+ }
+ return TRUE;
+}
+
+int Xdupdate(string str)
+{
+ int i, s;
+ object obj;
+ string file, *list;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xdu(pdate) <filename>");
+ if(!(file=XFindFile(str)))
+ return TRUE;
+ if(file[<2..<1]==".c")
+ file=file[0..<3];
+ if(obj=XFindObj(file))
+ {
+ PrintShort("Deep updating: ", obj);
+ list=inherit_list(obj);
+ for(s=sizeof(list); i<s; i++)
+ {
+ if(obj=find_object(list[i]))
+ Destruct(obj);
+ }
+ }
+ return TRUE;
+}
+
+int Xecho(string str)
+{
+ TK("Xecho: str: "+(str?str:"(NULL)"));
+ WLN(str);
+ return TRUE;
+}
+
+int Xeval(string str)
+{
+ object obj;
+ string file, error;
+ int *ru1, *ru2, xtime;
+ mixed res;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xev(al) <expression>");
+ file=LPC_FILE+".c";
+ if(file_size(file)>0)
+ rm(file);
+ if(obj=find_object(LPC_FILE))
+ Destruct(obj);
+#if 0
+ write_file(TOOL_LOG,
+ sprintf("%s (%s) xeval %s\n",
+ ctime(time()),getuid(cloner),str));
+#endif
+ write_file(file,
+ "#include <properties.h>\n"+
+ "#include <thing/properties.h>\n"+
+ "#include <defines.h>\n"+
+ "#include <wizlist.h>\n"+
+ "#include <moving.h>\n"+
+ "#include \"/secure/wizlevels.h\"\n"+
+ (file_size(PRIVATE_HEADER)>=0?"#include \""+PRIVATE_HEADER+"\"\n":"")+
+ "get(str){return previous_object()->XFindObj(str);}\n"+
+ "eval(me,here){return "+str+";}");
+ if(error=catch(obj=clone_object(file)))
+ W("Error: "+error[1..]);
+ else
+ {
+ ru1=rusage();
+ error=catch(res=(mixed)obj->eval(cloner, ENV(cloner)));
+ ru2=rusage();
+ if(error)
+ W("Error: "+error[1..]);
+ else
+ {
+ xtime=ru2[0]-ru1[0]+ru2[1]-ru1[1];
+ WDLN("Evaluation time: "+(xtime<0 ? 0 : xtime)+" ms");
+ PIPE_DELETE(pipe_of);
+ if(pipe_out&&pipe_of)
+ write_file(pipe_of,mixed_to_string(res,MAX_RECURSION)+"\n");
+ else
+ WLN("Result: "+mixed_to_string(res, MAX_RECURSION));
+ if(objectp(res))
+ variable["result"] = res;
+ }
+ }
+ rm(file);
+ if(obj)
+ Destruct(obj);
+ return TRUE;
+}
+
+int Xforall(string str)
+{
+ int i, s, t, u;
+ string pat, cmd, arg, *strs, *files, fh, fr, fe, ft, ff;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xfo(rall) <filepattern> <command>");
+ if(sscanf(str, "%s %s", pat, arg)!=2)
+ return FALSE;
+ files=long_get_dir(pat, FALSE);
+ if(!(s=sizeof(files)))
+ {
+ WDLN("No matching files found");
+ return TRUE;
+ }
+ strs=old_explode(files[0], "/");
+ fh="/";
+ if(t=sizeof(strs)-1)
+ fh+=implode(strs[0..t-1], "/");
+ for(i=0; i<s; i++)
+ {
+ ft=old_explode(files[i], "/")[t];
+ if((u=sizeof(strs=old_explode(ft, ".")))&&--u)
+ {
+ ff=implode(strs[0..u-1], ".");
+ fr=fh+"/"+ff;
+ fe=strs[u];
+ }
+ else
+ {
+ fe="";
+ ff=ft;
+ fr=files[i];
+ }
+ cmd=string_replace(arg, "!!", files[i]);
+ cmd=string_replace(cmd, "!e", fe);
+ cmd=string_replace(cmd, "!f", ff);
+ cmd=string_replace(cmd, "!h", fh);
+ cmd=string_replace(cmd, "!r", fr);
+ cmd=string_replace(cmd, "!t", ft);
+ if(!(Command(cmd)))
+ break;
+ }
+ return TRUE;
+}
+
+int Xgoto(string str)
+{
+ object obj, tmp;
+
+ SECURE2(TRUE);
+ USAGE1(str, "xgo(to) [object]");
+ if(!str) str="~/workroom";
+ if(!(obj=XFindObj(str)))
+ {
+ if(!(str=XFindFile(str)))
+ return TRUE;
+ if(catch(call_other(str, "???")))
+ return TRUE;
+ obj=find_object(str);
+ }
+ tmp=obj;
+ while(obj&&living(obj))
+ obj=ENV(obj);
+ cloner->move(obj ? obj : tmp, M_TPORT);
+ return TRUE;
+}
+
+int Xgrep(string str)
+{
+ int i, s, t, mode;
+ string *files, *ts;
+
+ SECURE2(TRUE);
+ TK("Xgrep: str: "+(str?str:"(NULL)"));
+ mode=0;
+ if(!pipe_in)
+ {
+ USAGE2(str, "xgr(ep) [-i] [-v] <regexp> <filepattern>");
+ if(!(ts=old_explode(str, " "))||!(s=sizeof(ts)))
+ return FALSE;
+ while(ts[0][0]=='-')
+ {
+ if(s<3)
+ {
+ WDLN("Too few arguments to xgrep");
+ return FALSE;
+ }
+ switch(ts[0])
+ {
+ case "-v":
+ mode|=XGREP_REVERT;
+ ts=ts[1..];
+ s--;
+ break;
+ case "-i":
+ mode|=XGREP_ICASE;
+ ts=ts[1..];
+ s--;
+ break;
+ case "-vi":
+ case "-iv":
+ mode|=XGREP_REVERT;
+ mode|=XGREP_ICASE;
+ ts=ts[1..];
+ s--;
+ break;
+ default:
+ WDLN("Unknown option "+ts[0]+" given to xgrep");
+ return FALSE;
+ }
+ }
+ str=implode(ts[0..s-2], " ");
+ }
+ else
+ {
+ if(!((ts=old_explode(str, " "))&&(s=sizeof(ts))))
+ USAGE3("xgr(ep) [-i] [-v] <regexp>");
+ while(ts[0][0]=='-')
+ {
+ if(s<2)
+ {
+ WDLN("Too few arguments to xgrep");
+ return FALSE;
+ }
+ switch(ts[0])
+ {
+ case "-v":
+ mode|=XGREP_REVERT;
+ ts=ts[1..];
+ s--;
+ break;
+ case "-i":
+ mode|=XGREP_ICASE;
+ ts=ts[1..];
+ s--;
+ break;
+ case "-iv":
+ case "-vi":
+ mode|=XGREP_REVERT;
+ mode|=XGREP_ICASE;
+ ts=ts[1..];
+ s--;
+ break;
+ default:
+ WDLN("Unknown option "+ts[0]+" given to xgrep");
+ return FALSE;
+ }
+ }
+ str=implode(ts[0..s-1], " ");
+ }
+
+ if(mode&XGREP_ICASE)
+ str=lower_case(str);
+ if(!(regexp(({"dummy"}), str)))
+ {
+ WDLN("Bad regular expression");
+ return TRUE;
+ }
+ if(!pipe_in)
+ {
+ if(file_size(TMP_FILE)>0)
+ rm(TMP_FILE);
+ if((t=sizeof(files=long_get_dir(XFile(ts[s-1]), FALSE)))&&
+ (file_size(files[0])>=0))
+ {
+ for(i=0; i<t; i++)
+ XGrepFile(str, files[i], mode);
+ if(pipe_out&&pipe_of)
+ {
+ PIPE_DELETE(pipe_of);
+ if(!pipe_ovr)
+ {
+ write_file(pipe_of,read_file(TMP_FILE,0,PIPE_MAX));
+ rm(TMP_FILE);
+ }
+ else
+ rename(TMP_FILE,pipe_of);
+ }
+ else
+ {
+ W(read_file(TMP_FILE,0,PIPE_MAX));
+ rm(TMP_FILE);
+ }
+ }
+ else
+ WDLN("Cannot read file(s)");
+ }
+ else
+ {
+ string *tmp;
+ if(file_size(pipe_if)<0)
+ {
+ WDLN("Missing input to xgrep");
+ return TRUE;
+ }
+ TK("Xgrep: str: "+str+" mode: "+mode);
+ s=sizeof(tmp=old_explode(read_file(pipe_if,0,PIPE_MAX),"\n"));
+ PIPE_DELETE(pipe_of);
+ for(i=0;i<s;i++)
+ {
+ // TK(tmp[i]+"<->"+str);
+ if(sizeof(regexp(({(mode&XGREP_ICASE?lower_case(tmp[i]):tmp[i])}),str)))
+ {
+ // TK("Xgrep: matched!");
+ if(!(mode&XGREP_REVERT))
+ if(pipe_out&&pipe_of)
+ write_file(pipe_of,tmp[i]+"\n");
+ else
+ WLN(tmp[i]);
+ }
+ else
+ if(mode&XGREP_REVERT)
+ if(pipe_out&&pipe_of)
+ write_file(pipe_of,tmp[i]+"\n");
+ else
+ WLN(tmp[i]);
+ }
+ }
+ return TRUE;
+}
+
+int Xhbeats(string str)
+{
+ object obj;
+ object *hbeatinfo;
+ string tmp, file;
+ int i, s;
+
+ SECURE2(TRUE);
+ TK("Xhbeats: str: "+(str?str:"(NULL)"));
+ if(!pipe_out)
+ {
+ USAGE1(str, "xhb(eats) [search pattern]");
+ if(!str)
+ str=RNAME(cloner);
+ else if(!regexp(({"dummy"}), str))
+ {
+ WDLN("Bad regular expression");
+ return TRUE;
+ }
+ }
+ else
+ {
+ USAGE1(str,"xhb(eats)");
+ if(str&&str!="")
+ {
+ WDLN("More arguments than expected");
+ return TRUE;
+ }
+ }
+ s=sizeof(hbeatinfo=heart_beat_info());
+ PIPE_DELETE(pipe_of);
+ for(i=0; i<s; i++)
+ if(hbeatinfo[i]&&objectp(hbeatinfo[i]))
+ {
+ tmp=ObjFile(hbeatinfo[i]);
+ if(sizeof(regexp(({tmp}), str)))
+ if(pipe_out&&pipe_of)
+ write_file(pipe_of, tmp+"\n");
+ else
+ WLN(tmp);
+ }
+ return TRUE;
+}
+
+int Xhead(string str)
+{
+ int lines;
+ string *tmp, file;
+
+ SECURE2(TRUE);
+ TK("Xhead: str: "+(str?str:"(NULL)"));
+ if(!pipe_in)
+ {
+ USAGE2(str, "xhead <-#> <file>");
+ if(sscanf(str,"-%d %s",lines,file)!=2)
+ return FALSE;
+ if(!(file=XFindFile(file)))
+ return FALSE;
+ }
+ else
+ {
+ USAGE2(str, "xhead <-#>");
+ if(sscanf(str,"-%d",lines)!=1)
+ return FALSE;
+ if (file_size(file=pipe_if)<0)
+ {
+ WDLN("Missing input to xhead");
+ return TRUE;
+ }
+ }
+ tmp=old_explode(read_file(file,0,PIPE_MAX),"\n")[0..lines-1];
+ if(pipe_in&&pipe_if==PIPE_FILE)
+ rm(PIPE_FILE);
+ if (pipe_out&&pipe_of)
+ {
+ PIPE_DELETE(pipe_of);
+ write_file(pipe_of,implode(tmp,"\n")+"\n");
+ }
+ else
+ WDLN(implode(tmp,"\n"));
+ return TRUE;
+}
+
+int Xhelp(string str)
+{
+ SECURE2(TRUE);
+ USAGE1(str, "xhe(lp)");
+ XMoreFile(TOOL_MANPAGE, FALSE);
+ return TRUE;
+}
+
+int Xids(string str)
+{
+ object obj;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xid(s) <object>");
+ TK("Xids: str: "+(str?str:"(NULL)"));
+ if((obj=XFindObj(str)))
+ WLN("UID=\""+getuid(obj)+"\" / EUID=\""+geteuid(obj)+"\"");
+ return TRUE;
+}
+
+int Xinfo(string str)
+{
+ object obj;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xinf(o) <object>");
+ TK("Xinfo: str: "+(str?str:"(NULL)"));
+ if((obj=XFindObj(str)))
+ {
+ if(is_player(obj))
+ {
+ WLN(PlayerWho(obj));
+ WLN(PlayerMail(obj, FALSE));
+ WLN(PlayerIP(obj, FALSE));
+ WLN(PlayerRace(obj, FALSE));
+ WLN(PlayerDomain(obj, FALSE));
+ WLN(PlayerStats(obj, FALSE));
+ WLN(PlayerSnoop(obj, FALSE));
+ }
+ else
+ WDLN("Sorry, this is not a player");
+ }
+ return TRUE;
+}
+
+int Xinherit(string str)
+{
+ int s;
+ object obj;
+ string *strs, *inlist;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xinh(erit) <object> [function]");
+ TK("Xinherit: str: "+str);
+ if(!(strs=strip_explode(str, " ")))
+ return FALSE;
+ if(obj=XFindObj(strs[0]))
+ {
+ inlist=inherit_list(obj);
+ s=sizeof(inlist);
+ while(s--)
+ {
+ if(catch(call_other(inlist[s], "???")))
+ {
+ WDLN("Failed to load all inheritance objects");
+ return TRUE;
+ }
+ }
+ obj=find_object(inlist[0]);
+ PIPE_DELETE(pipe_of);
+ if(sizeof(strs)==1)
+ Inheritance(obj ,0 ,"");
+ else
+ Inheritance(obj, strs[1], "");
+ }
+ return TRUE;
+}
+
+int Xinventory(string str)
+{
+ int i, short;
+ object item;
+ mixed who;
+
+ SECURE2(TRUE);
+ USAGE1(str, "xi [-s] [player]");
+ TK("Xinventory: str: "+str);
+ short=0;
+ who=cloner;
+ if(str&&str!="")
+ {
+ if(str=="-s")
+ {
+ short=1;
+ who=cloner;
+ }
+ else if(sscanf(str,"-s %s",who))
+ {
+ short=1;
+ who=XFindObj(who);
+ }
+ else if(sscanf(str,"%s",who))
+ {
+ short=0;
+ who=XFindObj(who);
+ }
+ else
+ who=cloner;
+ }
+ if(!who)
+ return FALSE;
+ PIPE_DELETE(pipe_of);
+ if(!(pipe_out&&pipe_of))
+ WLN(who->name(WESSEN)+" Inventory:"+(short?" (short)":""));
+ if(!short)
+ if(pipe_out&&pipe_of)
+ FORALL(item, who) PrintShort(ARIGHT(++i+". ", 4, " "), item, pipe_of);
+ else
+ FORALL(item, who) PrintShort(ARIGHT(++i+". ", 4, " "), item);
+ else
+ if(pipe_out&&pipe_of)
+ FORALL(item, who) write_file(pipe_of,++i+". ["+object_name(item)+"]\n");
+ else
+ FORALL(item, who) WLN(++i+". ["+object_name(item)+"]");
+ return TRUE;
+}
+
+int Xlag(string str)
+{
+ int i;
+ float *lag;
+ object daemon;
+ string lags;
+
+ if(file_size(LAG_O_DAEMON+".c")<=0)
+ {
+ WLN("Sorry, lag-o-daemon is missing!");
+ return TRUE;
+ }
+
+ LAG_O_DAEMON->MachHin();
+ if(!(daemon=find_object(LAG_O_DAEMON)))
+ lag=({-1.0,-1.0,-1.0});
+ else
+ lag=(float *)daemon->read_lag_data();
+ lags="Letzte 60 min: ";
+ if(lag[0]>=0.0)
+ {
+ for(i=round(lag[0])-1;i>=0;i--)
+ lags+="#";
+ lags+=" ("+sprintf("%.1f",lag[0])+"%)";
+ }
+ else
+ lags+="N/A";
+ lags+="\nLetzte 15 min: ";
+ if(lag[1]>=0.0)
+ {
+ for(i=round(lag[1])-1;i>=0;i--)
+ lags+="#";
+ lags+=" ("+sprintf("%.1f",lag[1])+"%)";
+ }
+ else
+ lags+="N/A";
+ lags+="\nLetzte Minute: ";
+ if(lag[2]>=0.0)
+ {
+ for(i=round(lag[2])-1;i>=0;i--)
+ lags+="#";
+ lags+=" ("+sprintf("%.1f",lag[2])+"%)";
+ }
+ else
+ lags+="N/A";
+ WLN(lags);
+ return TRUE;
+}
+
+int Xlight(string str)
+{
+ int s, addlight;
+
+ SECURE2(TRUE);
+ USAGE1(str, "xli(ght) [light]");
+ if(str)
+ {
+ if(!sscanf(str, "%d", addlight))
+ return FALSE;
+ xlight+=addlight;
+ cloner->AddIntLight(addlight);
+ }
+ WDLN("Current light levels: "+TOOL_NAME+"="+xlight+", room="+
+ ENV(cloner)->QueryIntLight());
+ return TRUE;
+}
+
+int Xload(string str)
+{
+ int i, f;
+ object obj, *inv, vroom;
+ string file, errlog, error, *strs;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xloa(d) <filename>");
+ if(!(file=XFindFile(str)))
+ return TRUE;
+ errlog=ERR_FILE;
+ if(file_size(errlog)>0)
+ rm(errlog);
+ if(obj=find_object(file))
+ {
+ if(catch(call_other(VOID, "???")))
+ {
+ WDLN("Error: cannot find "+VOID+" to rescue players");
+ return TRUE;
+ }
+ else
+ vroom = find_object(VOID);
+ if(inv=filter(all_inventory(obj), #'is_player, ME))//'
+ for(i=0; i<sizeof(inv); i++)
+ MoveObj(inv[i], vroom, TRUE);
+ Destruct(obj);
+ WLN("Update and load: "+file);
+ }
+ else
+ WLN("Load: "+file);
+ if(error=catch(call_other(file, "???")))
+ {
+ W("Error: "+error[1..]);
+ if(vroom)
+ tell_object(vroom, "*** Failed to load room. You are in the void!\n");
+ }
+ else if(inv)
+ {
+ obj=find_object(file);
+ for(i=0; i<sizeof(inv); i++)
+ if(inv[i])
+ MoveObj(inv[i], obj, TRUE);
+ }
+ return TRUE;
+}
+
+int Xlook(string str)
+{
+ object obj;
+ string st;
+ string file;
+
+ SECURE2(TRUE);
+ USAGE1(str, "xloo(k) [object]");
+ TK("Xlook: str: "+str);
+ PIPE_DELETE(pipe_of);
+ file = pipe_out&&pipe_of ? pipe_of : "";
+ if(str&&str!="")
+ {
+ if((obj=XFindObj(str)))
+ PrintObj(obj,file);
+ }
+ else
+ {
+ obj=ENV(cloner);
+ PrintObj(obj,file);
+ }
+ return TRUE;
+}
+
+int Xlpc(string str)
+{
+ object obj;
+ string file, error;
+ int *ru1, *ru2, time;
+ mixed res;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xlp(c) <lpc code>");
+ file=LPC_FILE+".c";
+ if(file_size(file)>0)
+ rm(file);
+ if(obj=find_object(LPC_FILE))
+ Destruct(obj);
+ write_file(file,
+ "#pragma no_warn_missing_return,strong_types,warn_deprecated,rtt_checks\n"
+ "#include <properties.h>\n"
+ "#include <thing/properties.h>\n"
+ "#include <defines.h>\n"
+ "#include <wizlist.h>\n"
+ "#include <moving.h>\n"
+ "#include \"/secure/wizlevels.h\"\n"
+ +(file_size(PRIVATE_HEADER)>=0?"#include \""+PRIVATE_HEADER+"\"\n":"")+
+ "object get(string str){return previous_object()->XFindObj(str);}\n"+
+ "mixed eval(mixed me, mixed here){"+str+"}");
+ if(error=catch(obj=clone_object(file)))
+ W("Error: "+error[1..0]);
+ else
+ {
+ ru1=rusage();
+ error=catch(res=(mixed)obj->eval(cloner, ENV(cloner)));
+ ru2=rusage();
+ if(error)
+ W("Error: "+error[1..]);
+ else
+ {
+ time=ru2[0]-ru1[0]+ru2[1]-ru1[1];
+ WDLN("Evaluation time: "+(time<0 ? 0 : time)+" ms");
+ WLN("Result: "+mixed_to_string(res, MAX_RECURSION));
+ if(objectp(res))
+ variable["result"] = res;
+ }
+ }
+ rm(file);
+ if(obj)
+ Destruct(obj);
+ return TRUE;
+}
+
+int Xman(string str)
+{
+ string manpage;
+ int i, found;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xma(n) <manpage>");
+ W("Man: ");
+ for(i=0, found=0; i<sizeof(manpath); i++)
+ {
+ manpage=manpath[i]+str;
+ if(file_size(manpage)>=0)
+ {
+ WLN(manpage);
+ XMoreFile(manpage, FALSE);
+ found=1;
+ break;
+ }
+ }
+ if(!found)
+ WLN("- no help available -");
+ return TRUE;
+}
+
+int Xmore(string str)
+{
+ string *args, file;
+ int line;
+
+ SECURE2(TRUE);
+ TK("Xmore: str: "+str);
+ if (!pipe_in)
+ {
+ USAGE2(str, "xmor(e) <filename> [start]");
+ switch(sizeof(args=strip_explode(str, " ")))
+ {
+ case 1:
+ moreoffset=1;
+ break;
+ case 2:
+ sscanf(args[1], "%d", line);
+ moreoffset= line>0 ? line : 1;
+ break;
+ default:
+ return FALSE;
+ }
+ if(file=XFindFile(args[0]))
+ XMoreFile(file, TRUE);
+ }
+ else
+ {
+ if(file_size(pipe_if)<0)
+ {
+ WDLN("Missing input to xmore");
+ return TRUE;
+ }
+ if (!str||str=="")
+ line=1;
+ else if (sscanf(str, "%d", line)!=1)
+ USAGE3("xmor(e) [start]");
+ moreoffset= line>0 ? line : 1;
+ XMoreFile(pipe_if, TRUE);
+ }
+ return TRUE;
+}
+
+int Xmove(string str)
+{
+ object obj1, obj2;
+ string what, into;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xmov(e) <object> into <object>");
+ if((sscanf(str, "%s into %s", what, into)==2)&&
+ (obj1=XFindObj(what))&&(obj2=XFindObj(into)))
+ MoveObj(obj1, obj2, FALSE);
+ return TRUE;
+}
+
+int Xmsg(string str)
+{
+ string tmp;
+
+ SECURE2(TRUE);
+ TK("Xmsg: str: "+str);
+ USAGE1(str, "xms(g) [to <object>|all]");
+ if(!str||str=="")
+ {
+ WDLN("Send message into room");
+ say("Message from "+CRNAME(cloner)+":\n");
+ if(pipe_in&&pipe_if)
+ say(read_file(pipe_if,0,PIPE_MAX));
+ else
+ {
+ WDLN("End message with \".\" or \"**\"");
+ input_to("XMsgSay");
+ }
+ return TRUE;
+ }
+ else if(sscanf(str, "to %s", tmp))
+ {
+ if(msgto=XFindObj(tmp))
+ {
+ PrintShort("Send message to: ", msgto);
+ tell_object(msgto, "Message from "+CRNAME(cloner)+" to you:\n");
+ if(pipe_in&&pipe_if)
+ tell_object(msgto,read_file(pipe_if,0,PIPE_MAX));
+ else
+ {
+ WDLN("End message with \".\" or \"**\"");
+ input_to("XMsgTell");
+ }
+ }
+ return TRUE;
+ }
+ else if(str=="all")
+ {
+ WDLN("Send message to all players");
+ shout("Message from "+CRNAME(cloner)+" to all:\n");
+ if(pipe_in&&pipe_if)
+ shout(read_file(pipe_if,0,PIPE_MAX));
+ else
+ {
+ WDLN("End message with \".\" or \"**\"");
+ input_to("XMsgShout");
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+int Xmtp(string str)
+{
+ int s;
+ string *strs, opt, dir, file;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xmt(p) [options] <directory> <filename>");
+ s=sizeof(strs=old_explode(str, " "));
+ if(s<2)
+ return FALSE;
+ else if(s==2)
+ opt="";
+ else
+ opt=implode(strs[0..s-3], " ");
+ if(!(dir="/"+(string)MASTER->valid_read(strs[s-2], geteuid(),
+ "get_dir", ME))) {
+ WDLN("No permission to open directory for reading");
+ return TRUE;
+ }
+ if(!(file="/"+(string)MASTER->valid_write(strs[s-1], geteuid(),
+ "write_file", ME))) {
+ WDLN("No permission to open script file for writing");
+ return TRUE;
+ }
+ if(file_size(dir)!=-2 || file_size(file)==-2)
+ return FALSE;
+ XmtpScript(dir, file, opt);
+ WDLN("Done");
+ return TRUE;
+}
+
+int Xproc(string str)
+{
+ int s;
+ string *strs;
+
+ SECURE2(TRUE);
+ USAGE1(str, "xproc [-c] [-l] [-m] [-u] [-v]");
+
+ if(file_size(TOOL_PATH+"/proc")!=-2)
+ {
+ WLN("Sorry, no /proc information available!");
+ return TRUE;
+ }
+
+ if(!str||str==""||!(s=sizeof(strs=old_explode(str, " "))))
+ {
+ WLN("Load averages:");
+ cat(TOOL_PATH+"/proc/loadavg");
+ return TRUE;
+ }
+
+ while(s=sizeof(strs))
+ {
+ switch(strs[0])
+ {
+ case "-c":
+ WLN("CPU info:");
+ cat(TOOL_PATH+"/proc/cpuinfo");
+ break;
+ case "-l":
+ WLN("Load averages:");
+ cat(TOOL_PATH+"/proc/loadavg");
+ break;
+ case "-m":
+ WLN("Memory usage:");
+ cat(TOOL_PATH+"/proc/meminfo");
+ break;
+ case "-u":
+ WLN("Uptime:");
+ cat(TOOL_PATH+"/proc/uptime");
+ break;
+ case "-v":
+ WLN("Version:");
+ cat(TOOL_PATH+"/proc/version");
+ break;
+ default:
+ WLN("Unknown option: "+strs[0]);
+ }
+ strs=strs[1..];
+ }
+ return TRUE;
+}
+
+int Xprof(string str)
+{
+ string *funcs, inh, tmp;
+ mixed *data, *d;
+ mapping xpr;
+ object obj;
+ int i, rn;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xprof <<-c>|<-C> <file>>|<object>");
+ if(str[0..2]=="-c "||str[0..2]=="-C ")
+ {
+ rn=(str[1]=='C');
+ if(str=XFindFile(str[3..]))
+ {
+ inh=str=str[0..<3];
+ if(obj=find_object(inh))
+ Destruct(obj);
+ if(catch(call_other(inh,"???")))
+ return TRUE;
+ obj=find_object(inh);
+ if(rn)
+ {
+ inh+=".xprof.c";
+ rm(inh);
+ str+=".c";
+ rename(str, inh);
+ }
+ else
+ {
+ str=XPROF_FILE;
+ rm(str);
+ }
+ tmp="inherit \""+inh+"\";\n#include \""+XPROF_MACRO+"\"\n";
+ funcs=m_indices(mkmapping(functionlist(obj, 0x08000001)))-({"__INIT"});
+ for(i=sizeof(funcs); i--;)
+ tmp+="F("+funcs[i]+",\""+funcs[i]+"\","+
+ "(A0,A1,A2,A3,A4,A5,A6,A7,A8,A9))\n";
+ write_file(str, tmp);
+ WDLN("Done");
+ }
+ }
+ else if(obj=XFindObj(str))
+ {
+ if(xpr=(mapping)obj->__query_xprof_data__())
+ {
+ funcs=m_indices(xpr);
+ data=m_values(xpr);
+ rm(TMP_FILE);
+ str="Evaluation cost per function:\nNAME "+
+ " CALLS | TOT.EXCL. TOT.INCL. | REL.EXCL. REL.INCL.\n";
+ for(i=sizeof(funcs); i--;)
+ {
+ if(d=data[i]) {
+ funcs[i]=ALEFT(""+funcs[i]+" ",25,".")+ARIGHT(" "+d[0], 6,".")+" | "+
+ ARIGHT(" "+d[1],10,".") +" "+ARIGHT(" "+d[3],10,".")+" | "+
+ ARIGHT(" "+d[1]/d[0],9,".") +" "+ARIGHT(" "+d[3]/d[0],9,".");
+ }
+ }
+ str+=implode(sort_array(funcs, "string_compare", ME),"\n")+"\n";
+ write_file(TMP_FILE,str);
+ str="\nElapsed time per function:\nNAME "+
+ " CALLS | TOT.EXCL. TOT.INCL. | REL.EXCL. REL.INCL.\n";
+ funcs=m_indices(xpr);
+ for(i=sizeof(funcs); i--;)
+ {
+ if(d=data[i])
+ {
+ funcs[i]=ALEFT(""+funcs[i]+" ",25,".")+ARIGHT(" "+d[0], 6,".")+" | "+
+ ARIGHT(" "+(d[2]+5)/10+"ms",10,".")+" "+
+ ARIGHT(" "+(d[4]+5)/10+"ms",10,".")+" | "+
+ ARIGHT(" "+d[2]/d[0]+"us",9,".")+" "+
+ ARIGHT(" "+d[4]/d[0]+"us",9,".");
+ }
+ }
+ str+=implode(sort_array(funcs, "string_compare", ME),"\n")+"\n";
+ write_file(TMP_FILE,str);
+ XMoreFile(TMP_FILE, FALSE);
+ }
+ else
+ WDLN("No profiling information available");
+ }
+ return TRUE;
+}
+
+int Xprops(string str)
+{
+ int i, s, flag;
+ object obj;
+ string *tmp;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xprop(s) [-f|-m] <object>");
+ TK("Xprops: str: "+str);
+ tmp=old_explode(str," ");
+ switch(tmp[0])
+ {
+ case "-f":
+ {
+ flag = 1;
+ tmp=tmp[1..];
+ break;
+ }
+ case "-m":
+ {
+ flag = 2;
+ tmp=tmp[1..];
+ break;
+ }
+ }
+ str=implode(tmp," ");
+ if((obj=XFindObj(str)))
+ DumpProperties(obj,flag);
+ return TRUE;
+}
+
+int Xquit(string str)
+{
+ SECURE2(TRUE);
+ USAGE1(str, "xqu(it)");
+ str=object_name(ENV(cloner));
+ if(member(str, '#')<0)
+ cloner->set_home(str);
+ cloner->quit();
+ return TRUE;
+}
+
+int Xscan(string str)
+{
+ SECURE2(TRUE);
+ USAGE1(str, "xsc(an)");
+ W("Destructed variable(s): ");
+ string* oldvars=m_indices(variable);
+ VarCheck(FALSE);
+ string* desvars=oldvars-m_indices(variable);
+ desvars = map(desvars, function string (string k)
+ {return "$"+k;} );
+ W(CountUp(desvars));
+ WLN("");
+ return TRUE;
+}
+
+int Xset(string str)
+{
+ int i;
+ mixed obj;
+ string name, tmp;
+
+ SECURE2(TRUE);
+ USAGE1(str, "xse(t) [$<name>=<object>]");
+ if(str) {
+ if(member(({"$me","$m","$here","$h"}),str)!=-1)
+ WDLN("Sorry, this is a reserved variable ["+str+"]");
+ else if(sscanf(str, "$%s=%s", name, tmp))
+ {
+ if(obj=XFindObj(tmp))
+ {
+ variable[name] = obj;
+ WLN(" $"+name+"="+ObjFile(obj));
+ }
+ }
+ else
+ return FALSE;
+ }
+ else
+ {
+ VarCheck(FALSE);
+ WLN("Current settings:");
+ foreach(string key, mixed val : variable)
+ {
+ if (val)
+ WLN(" $"+key+"="+ObjFile(val));
+ else
+ m_delete(variable, key);
+ }
+ WLN(" $me="+ObjFile(cloner));
+ WLN(" $here="+ObjFile(ENV(cloner)));
+ }
+ return TRUE;
+}
+
+int Xsh(string str)
+{
+ SECURE2(TRUE);
+ USAGE1(str, "xsh <filename>");
+ if(scriptline)
+ {
+ WDLN("Cannot execute another script file until last execution has ended");
+ return TRUE;
+ }
+ if(!(str=XFindFile(str)))
+ return TRUE;
+ str=read_file(str, 1, 1000);
+ if(!(scriptline=old_explode(str, "\n")))
+ {
+ WDLN("Bad script file");
+ return TRUE;
+ }
+ scriptsize=sizeof(scriptline);
+ XExecFile(NULL);
+ return TRUE;
+}
+
+int Xsort(string str)
+{
+ string *tmp,file;
+ int s,reverse;
+
+ SECURE2(TRUE);
+ TK("Xsort: str: "+str);
+ if(!pipe_in)
+ {
+ USAGE2(str, "xso(rt) [-r] [file]");
+ if(!(tmp=old_explode(str, " "))||(s=sizeof(tmp))>2)
+ return FALSE;
+ if(tmp[0]=="-r")
+ if(s==1)
+ return FALSE;
+ else
+ {
+ reverse=TRUE;
+ tmp=tmp[1..];
+ }
+ else if(s>1)
+ return FALSE;
+ if(!(file=XFindFile(tmp[0])))
+ {
+ WDLN("Can't find file");
+ return TRUE;
+ }
+ }
+ else
+ {
+ if(str&&str!="")
+ if(str=="-r")
+ reverse=TRUE;
+ else
+ USAGE3("xso(rt) [-r]");
+ if (file_size(file=pipe_if)<0)
+ {
+ WDLN("Missing input to xsort");
+ return TRUE;
+ }
+ }
+ tmp=old_explode(read_file(file,0,PIPE_MAX),"\n");
+ if(pipe_in&&pipe_if==PIPE_FILE)
+ rm(PIPE_FILE);
+ tmp=sort_array(tmp,reverse?#'<:#'>);
+ if (pipe_out&&pipe_of)
+ write_file(pipe_of,implode(tmp,"\n")+"\n");
+ else
+ WDLN(implode(tmp,"\n"));
+ return TRUE;
+}
+
+int Xtail(string str)
+{
+ string *tmp,file,sign;
+ int lines;
+
+ if (!str) {
+ WDLN("Missing input to xtail");
+ return TRUE;
+ }
+
+ sign="-";
+ lines=10;
+ SECURE2(TRUE);
+ TK("Xtail: str: "+str);
+ if(!pipe_in)
+ {
+ if(sscanf(str,"-%d %s",lines,file)==2)
+ sign="-";
+ else if(sscanf(str,"+%d %s",lines,file)==2)
+ sign="+";
+ else
+ file=str;
+
+ if(!(file=XFindFile(file)))
+ {
+ WDLN("Can't find file");
+ return TRUE;
+ }
+ }
+ else
+ {
+ if(sscanf(str,"-%d",lines)==1)
+ sign="-";
+ else if(sscanf(str,"+%d",lines)==1)
+ sign="+";
+ if (file_size(file=pipe_if)<0)
+ {
+ WDLN("Missing input to xtail");
+ return TRUE;
+ }
+ }
+
+ if(sign=="-")
+ {
+ if(!lines)
+ return TRUE;
+ }
+
+ if(file_size(file)>50000)
+ {
+ WDLN("File too large");
+ return TRUE;
+ }
+
+ if(sign=="+")
+ tmp=old_explode(read_file(file,0,PIPE_MAX),"\n")[lines..];
+ else
+ tmp=old_explode(read_file(file,0,PIPE_MAX),"\n")[<lines..];
+ if(pipe_in&&pipe_if==PIPE_FILE)
+ rm(PIPE_FILE);
+ if (pipe_out&&pipe_of)
+ write_file(pipe_of,implode(tmp,"\n")+"\n");
+ else
+ WLN(implode(tmp,"\n"));
+ return TRUE;
+}
+
+int Xtool(string str)
+{
+ int m;
+ string tmp;
+ object obj;
+
+ SECURE2(TRUE);
+ TK("Xtool: str: "+str);
+ USAGE1(str, "xto(ol) [update|first=<on|off>|protect=<on|off>|"+
+ "invcheck=<on|off>|\n"+
+ "\t\tvarcheck=<on|off>|scanchk=<on|off>|short=<on|off>|\n"+
+ "\t\techo=<on|off>|more=<amount>|kill|news|save|load|reset]");
+ if(str&&str!="")
+ {
+ if(sscanf(str, "more=%d", m))
+ {
+ if(m<5)
+ WDLN("Sorry, amount of lines should be more then 5");
+ else
+ {
+ WDLN("Setting amount of displayed lines to "+m);
+ morelines=m;
+ }
+ }
+ else
+ switch(str)
+ {
+ case "update":
+ if(obj=find_object(TOOL_PATH))
+ Destruct(obj);
+ if(catch(obj=clone_object(TOOL_PATH)))
+ WLN("Updating "+TOOL_TITLE+" failed!");
+ else
+ obj->update_tool(AUTOLOAD_ARGS, cloner);
+ return TRUE;
+ break;
+ case "first=on":
+ MODE_ON(MODE_FIRST);
+ move(cloner);
+ WDLN("Automatic moving into pole position of inventory turned on");
+ break;
+ case "first=off":
+ MODE_OFF(MODE_FIRST);
+ WDLN("Automatic moving into pole position of inventory turned off");
+ break;
+ case "protect=on":
+ MODE_ON(MODE_PROTECT);
+ WDLN("Protection from forces and illegal moves turned on");
+ break;
+ case "protect=off":
+ MODE_OFF(MODE_PROTECT);
+ WDLN("Protection from forces and illegal moves turned off");
+ break;
+ case "invcheck=on":
+ MODE_ON(MODE_INVCHECK);
+ WDLN("Automatic checking for new objects in inventory turned on");
+ break;
+ case "invcheck=off":
+ MODE_OFF(MODE_INVCHECK);
+ WDLN("Automatic checking for new objects in inventory turned off");
+ break;
+ case "varcheck=on":
+ MODE_ON(MODE_VARCHECK);
+ VarCheck(TRUE);
+ WDLN("Automatic variable checking turned on");
+ break;
+ case "varcheck=off":
+ MODE_OFF(MODE_VARCHECK);
+ WDLN("Automatic variable checking turned off");
+ break;
+ case "scanchk=on":
+ MODE_ON(MODE_SCANCHK);
+ WDLN("Scan check turned on");
+ break;
+ case "scanchk=off":
+ MODE_OFF(MODE_SCANCHK);
+ WDLN("Scan check turned off");
+ break;
+ case "echo=on":
+ MODE_ON(MODE_ECHO);
+ WDLN("Echoing of multiple command execution turned on");
+ break;
+ case "echo=off":
+ MODE_OFF(MODE_ECHO);
+ WDLN("Echoing of multiple command execution turned off");
+ break;
+ case "short=on":
+ MODE_ON(MODE_SHORT);
+ WDLN("Use of short descriptions turned on");
+ break;
+ case "short=off":
+ MODE_OFF(MODE_SHORT);
+ WDLN("Use of short descriptions turned off");
+ break;
+ case "kill":
+ WDLN(TOOL_NAME+" selfdestructs");
+ destruct(ME);
+ break;
+ case "news":
+ XMoreFile(TOOL_NEWS, FALSE);
+ break;
+ case "reset":
+ WDLN("Resetting "+TOOL_TITLE);
+ ME->__INIT();
+ break;
+ case "load":
+ if(file_size(SAVE_FILE+".o")>0)
+ {
+ WDLN("Loading "+TOOL_TITLE+" settings");
+ restore_object(SAVE_FILE);
+ }
+ else
+ WDLN("Sorry, cannot find file to load settings");
+ break;
+ case "save":
+ WDLN("Saving "+TOOL_TITLE+" settings");
+ save_object(SAVE_FILE);
+ break;
+ default:
+ return FALSE;
+ }
+ }
+ else
+ {
+ WLN(TOOL_TITLE+" settings:");
+ tmp= (" first .... = "+(MODE(MODE_FIRST) ? "on\n" : "off\n"));
+ tmp+=(" protect .. = "+(MODE(MODE_PROTECT) ? "on\n" : "off\n"));
+ tmp+=(" invcheck . = "+(MODE(MODE_INVCHECK) ? "on\n" : "off\n"));
+ tmp+=(" varcheck . = "+(MODE(MODE_VARCHECK) ? "on\n" : "off\n"));
+ tmp+=(" scanchk .. = "+(MODE(MODE_SCANCHK) ? "on\n" : "off\n"));
+ tmp+=(" echo ..... = "+(MODE(MODE_ECHO) ? "on\n" : "off\n"));
+ tmp+=(" short .... = "+(MODE(MODE_SHORT) ? "on\n" : "off\n"));
+ tmp+=(" more ..... = "+morelines);
+ WLN(sprintf("%-80#s", tmp));
+ }
+ return TRUE;
+}
+
+int Xtrace(string str)
+{
+ string file;
+ object obj;
+
+ SECURE2(TRUE);
+ USAGE1(str, "xtrac(e) <object>");
+ if(!str||str=="")
+ {
+ trace(0);
+ WDLN("Ending trace ["+short_path("/"+traceprefix(0))+"]");
+ }
+ else if(obj=XFindObj(str))
+ {
+ PrintShort("Tracing: ", obj);
+ file=object_name(obj);
+ file=file[1..<1];
+ traceprefix(file);
+ trace(TRACE_LEVEL);
+ }
+ return TRUE;
+}
+
+int Xtrans(string str)
+{
+ object obj;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xtran(s) <object>");
+ if((obj=XFindObj(str))&&ENV(obj))
+ {
+ tell_room(ENV(obj), CRNAME(obj)+" vanishes.\n");
+ tell_room(ENV(cloner), CRNAME(obj)+
+ " is teleported into this room by "+CRNAME(cloner)+".\n");
+ MoveObj(obj, ENV(cloner), TRUE);
+ tell_object(obj, "You've been teleported to "+CRNAME(cloner)+".\n");
+ }
+ else
+ WDLN("Failed to teleport object");
+ return TRUE;
+}
+
+int Xupdate(string str)
+{
+ object obj;
+ string file;
+
+ SECURE2(TRUE);
+ USAGE2(str, "xup(date) <filename>");
+ if(!(file=XFindFile(str)))
+ return TRUE;
+ if(file[<2.. <1]==".c")
+ file=file[0.. <3];
+ if((obj=XFindObj(file))&&(obj=find_object(pure_file_name(obj))))
+ {
+ PrintShort("Updating: ", obj);
+ Destruct(obj);
+ }
+ else
+ WDLN("Object not found");
+ return TRUE;
+}
+
+int Xuptime(string str)
+{
+ return TRUE;
+}
+
+int Xwc(string str)
+{
+ string file;
+ string tmp, *tmp2;
+ int i, chars, words, lines, nchars, nwords, nlines;
+
+ SECURE2(TRUE);
+ TK("Xwc: str: "+str);
+ chars=words=lines=FALSE;
+ if(!pipe_in)
+ {
+ USAGE2(str, "xwc [-cwl] <file>");
+ if(str[0]=='-')
+ {
+ while((str=str[1..])[0]!=' '&&sizeof(str))
+ switch(str[0])
+ {
+ case 'c':
+ chars=TRUE;
+ break;
+ case 'w':
+ words=TRUE;
+ break;
+ case 'l':
+ lines=TRUE;
+ break;
+ default:
+ return FALSE;
+ }
+ str=str[1..];
+ }
+ if(!(file=XFindFile(str)))
+ {
+ WDLN("Can't find file");
+ return TRUE;
+ }
+ }
+ else
+ {
+ USAGE1(str,"xwc [-cwl]");
+ if(str)
+ if(str[0]=='-')
+ {
+ while((str=str[1..])[0]!=' '&&sizeof(str))
+ switch(str[0])
+ {
+ case 'c':
+ chars=TRUE;
+ break;
+ case 'w':
+ words=TRUE;
+ break;
+ case 'l':
+ lines=TRUE;
+ break;
+ default:
+ return FALSE;
+ }
+ }
+ else
+ return FALSE;
+ if(file_size(file=pipe_if)<0)
+ {
+ WDLN("Missing input to xwc");
+ return TRUE;
+ }
+ }
+ if(!(chars|words|lines))
+ chars=words=lines=TRUE;
+ nlines=nwords=nchars=0;
+ tmp=read_file(file,0,PIPE_MAX);
+ tmp2=explode(tmp,"\n");
+ if(lines)
+ {
+ nlines=sizeof(tmp2);
+ if(tmp2[<1]==""&&nlines>1)
+ nlines--;
+ }
+ if(words)
+ for(i=sizeof(tmp2)-1;i>=0;i--)
+ {
+ TK(sprintf("%O",tmp2[i]));
+ if(tmp2[i]!="")
+ nwords+=sizeof(regexplode(tmp2[i],"[ ]")-({""," "," "}));
+ TK(sprintf("%O",regexplode(tmp2[i],"[ ]")-({""," "," "})));
+ TK("nwords: "+nwords);
+ }
+ if(chars)
+ for(i=sizeof(tmp2)-1;i>=0;i--)
+ nchars+=sizeof(tmp2[i])+1;
+ tmp2=0;
+ tmp="";
+ if(lines)
+ tmp+=sprintf("%7d",nlines)+" ";
+ if(words)
+ tmp+=sprintf("%7d",nwords)+" ";
+ if(chars)
+ tmp+=sprintf("%7d",nchars)+" ";
+ if(file!=pipe_if)
+ tmp+=file;
+ WLN(tmp);
+ return TRUE;
+}
+
+int cmdavg_compare(string a, string b)
+{
+ int x,y;
+ string dum;
+ sscanf(a,"%s cmdavg: %d",dum,x);
+ sscanf(b,"%s cmdavg: %d",dum,y);
+ return x==y?0:(x>y?1:-1);
+}
+
+int Xwho(string opt)
+{
+ string *strs,str,func;
+
+ SECURE2(TRUE);
+ TK("Xwho: opt: \""+opt+"\"");
+ USAGE1(opt, "xwh(o) [mail|ip|race|guild|domain|stats|snoop]");
+ func="string_compare";
+ if(!opt||opt=="")
+ strs=map(users(), "PlayerWho", ME);
+ else
+ switch(opt)
+ {
+ case "mail":
+ strs=map(users(), "PlayerMail", ME, TRUE);
+ break;
+ case "ip":
+ strs=map(users(), "PlayerIP", ME, TRUE);
+ break;
+ case "race":
+ case "guild":
+ strs=map(users(), "PlayerRace", ME, TRUE);
+ break;
+ case "domain":
+ strs=map(users(), "PlayerDomain", ME, TRUE);
+ break;
+ case "stat":
+ case "stats":
+ strs=map(users(), "PlayerStats", ME, TRUE);
+ break;
+ case "snoop":
+ strs=map(users(), "PlayerSnoop", ME, TRUE);
+ break;
+ case "cmdavg":
+ strs=map(users(), "PlayerCmdAvg", ME, TRUE);
+ func="cmdavg_compare";
+ break;
+ default:
+ return FALSE;
+ }
+ strs=sort_array(strs, func, ME);
+ if(pipe_out&&pipe_of)
+ write_file(pipe_of,implode(strs,"\n")+"\n");
+ else
+ WLN(implode(strs,"\n"));
+ return TRUE;
+}
diff --git a/obj/tools/MGtool/toollib.c b/obj/tools/MGtool/toollib.c
new file mode 100644
index 0000000..9464004
--- /dev/null
+++ b/obj/tools/MGtool/toollib.c
@@ -0,0 +1,192 @@
+/*
+ * MGtool-1.0
+ * File: toollib.c
+ * Maintainer: Kirk@MorgenGrauen
+ */
+
+/*------------------------------------------*/
+/* the original Xtool is copyrighted by Hyp */
+/*------------------------------------------*/
+
+#include "toollib.h"
+#include <lpctypes.h>
+#include <properties.h>
+/*
+string *old_explode(string str, string del)
+{
+ int s, t;
+ string *strs;
+
+ if(del == "")
+ return ({str});
+ strs=explode(str, del);
+ s=0;
+ t=sizeof(strs)-1;
+ while(s<=t && strs[s++] == "")
+ ;
+ s--;
+ while(t>=0 && strs[t--] == "")
+ ;
+ t++;
+ if(s<=t)
+ return strs[s..t];
+ return 0;
+}
+
+string *explode(string str, string del)
+{
+ return explode(str, del);
+}
+*/
+string *strip_explode(string str, string del)
+{
+ return explode(str, del)-({""});
+}
+
+string strip_string(string str)
+{
+ return implode(strip_explode(str," ")," ");
+}
+
+int string_compare(string a, string b)
+{
+ return a==b?0:(a>b?1:-1);
+}
+
+string cap_string(string str)
+{
+ return capitalize(str);
+}
+
+string short_path(string file)
+{
+ int s;
+ string tmp;
+
+ if(!file)
+ return 0;
+ if(PL)
+ {
+ if(file[0.. 8]=="/players/")
+ {
+ s=sizeof(getuid(PL))+8;
+ return "~"+(file[9.. s]==getuid(PL) ?
+ file[s+1.. <1] : file[9.. <1]);
+ }
+ }
+ if(file[0.. 2]=="/d/")
+ return "+"+file[3.. <1];
+ else
+ return file;
+}
+
+string long_path(string file)
+{
+ return (string)MASTER->make_path_absolute(file);
+}
+
+string *long_get_dir(string pat, int all)
+{
+ int i, s;
+ string str, dir, *file, *tmp;
+
+ if(!pat)
+ return ({});
+ pat=long_path(pat);
+ if(tmp=old_explode(pat, "/"))
+ dir="/"+implode(tmp[0..sizeof(tmp)-2], "/")+"/";
+ else
+ dir="/";
+ s=sizeof(tmp=get_dir(pat));
+ file=({});
+ for(i=0;i<s;i++)
+ {
+ str=dir+tmp[i];
+ if(all||file_size(str)>=0)
+ file+=({str});
+ }
+ return file;
+}
+
+string lit_string(string str)
+{
+ str=string_replace(str, "\\", "\\\\");
+ str=string_replace(str, "\b", "\\b");
+ str=string_replace(str, "\n", "\\n");
+ str=string_replace(str, "\r", "\\r");
+ str=string_replace(str, "\t", "\\t");
+ return string_replace(str, "\"", "\\\"");
+}
+
+string mixed_to_string(mixed mix, int lvl)
+{
+ int i, j, s, t;
+ string str;
+ mixed *keys;
+
+ if(lvl)
+ {
+ switch(typeof(mix))
+ {
+ default:
+ case T_INVALID:
+ return "<invalid>";
+ case T_STRUCT:
+ return to_string(mix);
+ case T_LVALUE:
+ return "&"+mixed_to_string(mix, lvl-1);
+ case T_NUMBER:
+ case T_FLOAT:
+ return to_string(mix);
+ case T_STRING:
+ return "\""+lit_string(mix)+"\"";
+ case T_POINTER:
+ return "({"+implode(map(mix,"mixed_to_string",ME,lvl-1),",")+"})";
+ case T_OBJECT:
+ return "["+short_path(object_name((object)mix))+"]";
+ case T_MAPPING:
+ s=sizeof(keys=m_indices(mix));
+ t=get_type_info(mix, 1);
+ str="([";
+ for(i=0;i<s;i++)
+ {
+ str+=mixed_to_string(keys[i], lvl-1);
+ if(t)
+ {
+ str+=":"+mixed_to_string(mix[keys[i],0], lvl-1);
+ for(j=1;j<t;j++)
+ str+=";"+mixed_to_string(mix[keys[i],j], lvl-1);
+ }
+ if(i<s-1) str+=",";
+ }
+ return str+"])";
+ case T_CLOSURE:
+ case T_SYMBOL:
+ return sprintf("%O", mix);
+ case T_QUOTED_ARRAY:
+ return "'"+mixed_to_string(funcall(lambda(0, mix)), lvl-1);
+ }
+ }
+ return "...";
+}
+
+int is_player(object obj)
+{
+ return is_obj(obj)&&query_once_interactive(obj);
+}
+
+int is_not_player(object obj)
+{
+ return is_obj(obj)&&!is_player(obj);
+}
+
+int round(float val)
+{
+ int tmp;
+
+ tmp=(int)val;
+ // only positive val
+ if( val - tmp >= 0.5 )
+ return tmp+1;
+ return tmp;
+}
diff --git a/obj/tools/MGtool/toollib.h b/obj/tools/MGtool/toollib.h
new file mode 100644
index 0000000..69e8264
--- /dev/null
+++ b/obj/tools/MGtool/toollib.h
@@ -0,0 +1,48 @@
+/*
+ * MGtool-1.0
+ * File: toollib.h
+ * Maintainer: Kirk@MorgenGrauen
+ */
+
+/*------------------------------------------*/
+/* the original Xtool is copyrighted by Hyp */
+/*------------------------------------------*/
+
+#ifndef __TOOLLIB_H__
+#define __TOOLLIB_H__ 1
+
+#ifndef MASTER
+#define MASTER __MASTER_OBJECT__
+#endif
+
+#define is_obj(x) ((x)&&objectp(x))
+
+#define is_living(x) (is_obj(x)&&living(x))
+#define is_not_living(x) (is_obj(x)&&!is_living(x))
+#define is_netdead(x) (is_obj(x)&&is_player(x)&&!interactive(x))
+#define is_alive(x) (is_obj(x)&&is_player(x)&&interactive(x))
+#define is_snooped(x) (is_obj(x)&&objectp(query_snoop(x)))
+#define is_not_snooped(x) (is_obj(x)&&!is_snooped(x))
+#define is_invis(x) (is_obj(x)&&((x)->QueryProp(P_INVIS)||!(x)->QueryProp(P_SHORT))))
+#define is_not_invis(x) (is_obj(x)&&!is_invis(x))
+
+#define pure_file_name(x) (is_obj(x)?old_explode(object_name(x),"#")[0]:0)
+#define source_file_name(x) (is_obj(x)?pure_file_name((x))+".c":0)
+#define string_replace(x,y,z) implode(explode((x),(y)),(z))
+
+int string_compare(string a, string b);
+string cap_string(string str);
+string short_path(string file);
+string long_path(string file);
+//string *old_explode(string str, string del);
+//string *explode(string str, string del);
+string *strip_explode(string str, string del);
+string strip_string(string str);
+string *long_get_dir(string pat, int all);
+string lit_string(string str);
+string mixed_to_string(mixed mix, int level);
+int is_player(object obj);
+int is_not_player(object obj);
+int round(float val);
+
+#endif /* __TOOLLIB_H__ */