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__ */