mushpp - Unformat and process MUSH/MUX code.


mushpp [options] [files]


Mushpp is a Perl script to process formatted MUSH/MUX code with comments, defines and macros into something a MUSH/MUX can handle.


-o command, --outputcommand=command

Prefix all status or warning messages with 'command', e.g.:

 mushpp --outputcommand=/echo fnord.mush
-f message, --finishmessage=message

Print message when processing is finished, e.g.:

 mushpp --finishmessage=Uploaded. fnord.mush

This message isn't printed at all if the quiet option is used, and is prefixed by the outputcommand, if specified.

-d, --define=macro[=value]

This adds a macro with with the specified value, with a default value of ``1''. This is useful for enabling #ifdef-ed sections of files. See Defines and Conditionals below.

-q, --quiet

Quiet status messages such as the uploaded message. Issue this option two or more times to silence even error output. (Be careful with this.)

-v, --version

Show the version and exit.

-h, --help

Show a short usage statement and exit.

-H, --man

Show this documentation.


The files processed by mushpp will be de-indented and newlines up to a line containing only a '-' or 'EOL' will be compressed into one line.

Lines starting with # are comments, except for some special cases. No leading white space is allowed. See Preprocessor Directives below.

You can inline comments with /@@ text @@/, but they can't span lines like C's /* */ comments.


 &foo me=$foo *:
   @switch %0=bar,{ /@@ Correct 'password'. @@/
     @pemit me=Foo
   },{ /@@ Incorrect 'password'. @@/
     @pemit me=Huh?
 @pemit me=Don't forget that anybody can use the foo%b
           command if they're in the same location as%b
           you or in your inventory!

When run through mushpp will look like:

 &foo me=$foo *:@switch %0=bar,{ @pemit me=Foo},{ @pemit me=Huh?}
 @pemit me=Don't forget that anybody can use the foo%bcommand if they're in the same location as%byou or in your inventory!

Preprocessor Directives


You can use #define in a similar way to the C preprocessor. Be aware macros are case sensitive. Leading white space is allowed. For example:

 #define FOO BAR
  # define   BAR   BAZ
 @pemit me=FOO
 @pemit me=foo

Will result in:

 @pemit me=BAZ
 @pemit me=foo


You can also define macros:

 #define PEM(BAR, BAZ) switch(isdbref(BAR),1,pemit(BAR,BAZ),0,pemit(*BAR,BAZ))
 think [PEM(me, fnord)]
 think [PEM(

Will result in:

 think [switch(isdbref(me),1,pemit(me,fnord),0,pemit(*me,fnord))]
 think [switch(isdbref(#1234),1,pemit(#1234,fnordfnord),0,pemit(*#1234,fnordfnord))]

You may have a macro that spans multiple lines if you use a backspace to continue the line to the next line. Leading whitespace from continued lines is removed. For example:

 #define LONGMACRO(_string_) This is a long macro \
                             that prints _string_.
 LONGMACRO(some random string)

Will result in:

 This is a long macro that prints some random string.

There is no check for a \\ type pattern at the end of a line, so you can't ``escape'' the backslash at the end of a macro definition.

During macro substitution, there is a special check for ``\,'' strings, which allows you to have a comma in a provided argument. Doubled backslashes are reduced to one backslash, thus allowing you to get a literal ``\,'' string by using ``\\\,''. Any other backslashed character will result in a literal backslash and that character.

ASCII defines

The special directive #ascii name ... #endascii will MUSH-escape the block of text between #ascii and #endascii and assign it to the name definition. For example:

  .-.   .-. 
 .   \o/   .
 `._  U  _.'
  .'  U  `.

Will result in:


Note that there's a leading and trailing blank line in this example; if you don't include them there will be no leading and trailing %r on the output whenever BUTTERFLY is used, which may or may not be desired.

Also note that ASCII blocks are not examined for other defines and macros. They are processed and output as-is.

Evaluated defines

The special directive #eval_define uses Perl to evaluate the definition and put the result into the definition name, but you can not use this to create macros. Be careful with this, as there's no input sanity checking; the code is procesed for macros then pased directly to the Perl interpreter. Example:

 #eval_define FOO  0x1
 #eval_define BAR  0x2
 #eval_define BAZ  0x4
 #eval_define ALL  FOO | BAR | BAZ

Will result in:

 1 2 4 7


You can use #ifdef/#ifndef ... [#else ...] #endif to conditionally include sections in the processed output. Conditionals can be nested within each other. Example:

 #define FOO 1
 #ifdef FOO
 foo is defined
 #ifndef BAR
 bar is not defined
 #ifdef BAZ
 baz is defined
 baz is not defined

This will result in:

 foo is defined
 bar is not defined
 baz is not defined

Currently there are no #if, #elif, or #elifdef directives.


You can use #include to include another file for processing. The file is first looked for in the current directory, then in the directory the current file being processed resides in. For example, if ``defines.mux'' contained:

 #define MYNAME Foo
 #define MYDBREF #1234

And you processed the following:

 #include defines.mux
 @pemit me=
  My name: MYNAME%r
  My dbref: MYDBREF

This will result in:

 @pemit me=My name: Foo%rMy dbref: #1234


You can fairly easily use this within TinyFugue with the following macro:

 /def upload = /quote -dexec -0 !mushpp -o /echo %*

Then from within TinyFugue you can simply issue a command such as ``/upload fnord.mux'' and fnord.mux would be processed and sent to your current (foreground) world.

A more complex TinyFugue macro that lets you either process data directly from the TinyFugue input area or a file if a filename is provided as an argument:

 /if ( {TMPDIR} =~ "" ) \
   /setenv TMPDIR=/tmp %;\
 /def -i mushpp = \
   /if ({#} >= 1) \
     /quote -dexec -0 !~/bin/mushpp -o /echo -f Uploaded. %* %; \
     /return %; \
   /endif %; \
   /let tmpfile=$[strcat({TMPDIR}, '/tf-tmp.', rand(10000, 99999))] %; \
   /let f=$[tfopen({tmpfile}, 'w')] %; \
   /if ({f} == -1) \
     /echo -e %% Unable to open %tmpfile for writing. %; \
     /return %; \
   /endif %; \
   /echo -e %% Entering pipe mode.  Type "." to end. %; \
   /let _line=%; \
   /while ((tfread(_line)) >= 0 & _line !/ ".") \
     /@test tfwrite({f}, strcat(_line, \n)) %; \
   /done %; \
   /test $[tfclose({f})] %; \
   /quote -dexec -S !~/bin/mushpp -o /echo %tmpfile %; \
   /quote -decho -S !/bin/rm %tmpfile


There are three standard exit codes:


If you spot any other serious bugs, please email the author (see below).


Christian J. Robinson <>


Copyright 2003-2010 Christian J. Robinson <>

Ideas, but no code borrowed from ( written by Adam Dray <>.

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

Or on the web: