src/boolexp.c File Reference

#include "copyright.h"
#include "config.h"
#include "db.h"
#include "match.h"
#include "mudconf.h"
#include "externs.h"
#include "interface.h"
#include "attrs.h"
#include "flags.h"
#include "powers.h"
#include "alloc.h"

Include dependency graph for boolexp.c:

Go to the source code of this file.

Functions

static int check_attr (dbref player, dbref lockobj, ATTR *attr, char *key)
int eval_boolexp (dbref player, dbref thing, dbref from, BOOLEXP *b)
int eval_boolexp_atr (dbref player, dbref thing, dbref from, char *key)
static void skip_whitespace (void)
static BOOLEXPparse_boolexp_E (void)
static BOOLEXPtest_atr (char *s)
static BOOLEXPparse_boolexp_L (void)
static BOOLEXPparse_boolexp_F (void)
static BOOLEXPparse_boolexp_T (void)
BOOLEXPparse_boolexp (dbref player, const char *buf, int internal)

Variables

static int parsing_internal = 0
static const char * parsebuf
static char parsestore [LBUF_SIZE]
static dbref parse_player


Function Documentation

static int check_attr ( dbref  player,
dbref  lockobj,
ATTR attr,
char *  key 
) [static]

Indicate if attribute ATTR on player passes key when checked by the object lockobj

Definition at line 24 of file boolexp.c.

References A_LENTER, A_NAME, atr_pget(), attr, free_lbuf, attr::number, See_attr, and wild_match().

Referenced by eval_boolexp().

00025 {
00026         char *buff;
00027         dbref aowner;
00028         int aflags, checkit;
00029 
00030         buff = atr_pget(player, attr->number, &aowner, &aflags);
00031         checkit = 0;
00032 
00033         if(attr->number == A_LENTER) {
00034                 /* We can see enterlocks... else we'd break zones */
00035                 checkit = 1;
00036         } else if(See_attr(lockobj, player, attr, aowner, aflags)) {
00037                 checkit = 1;
00038         } else if(attr->number == A_NAME) {
00039                 checkit = 1;
00040         }
00041         if(checkit && (!wild_match(key, buff))) {
00042                 checkit = 0;
00043         }
00044         free_lbuf(buff);
00045         return checkit;
00046 }                                                               /* end check_attr() */

int eval_boolexp ( dbref  player,
dbref  thing,
dbref  from,
BOOLEXP b 
)

Definition at line 48 of file boolexp.c.

References A_LENTER, A_LOCK, A_NAME, alloc_lbuf, alloc_mbuf, atr_get(), atr_num(), atr_pget(), BOOLEXP_AND, BOOLEXP_ATR, BOOLEXP_CARRY, BOOLEXP_CONST, BOOLEXP_EVAL, BOOLEXP_INDIR, BOOLEXP_IS, BOOLEXP_NOT, BOOLEXP_OR, BOOLEXP_OWNER, c, check_attr(), Contents, DOLIST, ENDLOG, EV_EVAL, EV_FIGNORE, EV_TOP, eval_boolexp(), eval_boolexp_atr(), exec(), free_lbuf, free_mbuf, INDIR_TOKEN, statedata::lock_nest_lev, confdata::lock_nest_lim, LOG_BUGS, log_name_and_loc(), log_text(), member(), mudconf, mudstate, notify, attr::number, Owner, Read_attr, STARTLOG, string_compare(), boolexp::sub1, boolexp::sub2, boolexp::thing, TRUE_BOOLEXP, and boolexp::type.

Referenced by eval_boolexp(), eval_boolexp_atr(), and fun_elock().

00049 {
00050         dbref aowner, obj, source;
00051         int aflags, c, checkit;
00052         char *key, *buff, *buff2, *bp, *str;
00053         ATTR *a;
00054 
00055         if(b == TRUE_BOOLEXP)
00056                 return 1;
00057 
00058         switch (b->type) {
00059         case BOOLEXP_AND:
00060                 return (eval_boolexp(player, thing, from, b->sub1) &&
00061                                 eval_boolexp(player, thing, from, b->sub2));
00062         case BOOLEXP_OR:
00063                 return (eval_boolexp(player, thing, from, b->sub1) ||
00064                                 eval_boolexp(player, thing, from, b->sub2));
00065         case BOOLEXP_NOT:
00066                 return !eval_boolexp(player, thing, from, b->sub1);
00067         case BOOLEXP_INDIR:
00068                 /*
00069                  * BOOLEXP_INDIR (i.e. @) is a unary operation which is replaced at
00070                  * evaluation time by the lock of the object whose number is the
00071                  * argument of the operation.
00072                  */
00073 
00074                 mudstate.lock_nest_lev++;
00075                 if(mudstate.lock_nest_lev >= mudconf.lock_nest_lim) {
00076 //            log_error(LOG_BUGS, "BUG", "LOCK", "
00077                         STARTLOG(LOG_BUGS, "BUG", "LOCK") {
00078                                 log_name_and_loc(player);
00079                                 log_text((char *) ": Lock exceeded recursion limit.");
00080                                 ENDLOG;
00081                         } notify(player, "Sorry, broken lock!");
00082                         mudstate.lock_nest_lev--;
00083                         return (0);
00084                 }
00085                 if((b->sub1->type != BOOLEXP_CONST) || (b->sub1->thing < 0)) {
00086                         STARTLOG(LOG_BUGS, "BUG", "LOCK") {
00087                                 log_name_and_loc(player);
00088                                 buff = alloc_mbuf("eval_boolexp.LOG.indir");
00089                                 sprintf(buff, ": Lock had bad indirection (%c, type %d)",
00090                                                 INDIR_TOKEN, b->sub1->type);
00091                                 log_text(buff);
00092                                 free_mbuf(buff);
00093                                 ENDLOG;
00094                         }
00095                         notify(player, "Sorry, broken lock!");
00096                         mudstate.lock_nest_lev--;
00097                         return (0);
00098                 }
00099                 key = atr_get(b->sub1->thing, A_LOCK, &aowner, &aflags);
00100                 c = eval_boolexp_atr(player, b->sub1->thing, from, key);
00101                 free_lbuf(key);
00102                 mudstate.lock_nest_lev--;
00103                 return (c);
00104         case BOOLEXP_CONST:
00105                 return (b->thing == player || member(b->thing, Contents(player)));
00106         case BOOLEXP_ATR:
00107                 a = atr_num(b->thing);
00108                 if(!a)
00109                         return 0;                       /*
00110                                                                  * no such attribute 
00111                                                                  */
00112 
00113                 /*
00114                  * First check the object itself, then its contents 
00115                  */
00116 
00117                 if(check_attr(player, from, a, (char *) b->sub1))
00118                         return 1;
00119                 DOLIST(obj, Contents(player)) {
00120                         if(check_attr(obj, from, a, (char *) b->sub1))
00121                                 return 1;
00122                 }
00123                 return 0;
00124         case BOOLEXP_EVAL:
00125                 a = atr_num(b->thing);
00126                 if(!a)
00127                         return 0;                       /*
00128                                                                  * no such attribute 
00129                                                                  */
00130                 source = from;
00131                 buff = atr_pget(from, a->number, &aowner, &aflags);
00132                 if(!buff || !*buff) {
00133                         free_lbuf(buff);
00134                         buff = atr_pget(thing, a->number, &aowner, &aflags);
00135                         source = thing;
00136                 }
00137                 checkit = 0;
00138 
00139                 if((a->number == A_NAME) || (a->number == A_LENTER)) {
00140                         checkit = 1;
00141                 } else if(Read_attr(source, source, a, aowner, aflags)) {
00142                         checkit = 1;
00143                 }
00144                 if(checkit) {
00145                         buff2 = bp = alloc_lbuf("eval_boolexp");
00146                         str = buff;
00147                         exec(buff2, &bp, 0, source, player,
00148                                  EV_FIGNORE | EV_EVAL | EV_TOP, &str, (char **) NULL, 0);
00149                         *bp = '\0';
00150                         checkit = !string_compare(buff2, (char *) b->sub1);
00151                         free_lbuf(buff2);
00152                 }
00153                 free_lbuf(buff);
00154                 return checkit;
00155         case BOOLEXP_IS:
00156 
00157                 /*
00158                  * If an object check, do that 
00159                  */
00160 
00161                 if(b->sub1->type == BOOLEXP_CONST)
00162                         return (b->sub1->thing == player);
00163 
00164                 /*
00165                  * Nope, do an attribute check 
00166                  */
00167 
00168                 a = atr_num(b->sub1->thing);
00169                 if(!a)
00170                         return 0;
00171                 return (check_attr(player, from, a, (char *) (b->sub1)->sub1));
00172         case BOOLEXP_CARRY:
00173 
00174                 /*
00175                  * If an object check, do that 
00176                  */
00177 
00178                 if(b->sub1->type == BOOLEXP_CONST)
00179                         return (member(b->sub1->thing, Contents(player)));
00180 
00181                 /*
00182                  * Nope, do an attribute check 
00183                  */
00184 
00185                 a = atr_num(b->sub1->thing);
00186                 if(!a)
00187                         return 0;
00188                 DOLIST(obj, Contents(player)) {
00189                         if(check_attr(obj, from, a, (char *) (b->sub1)->sub1))
00190                                 return 1;
00191                 }
00192                 return 0;
00193         case BOOLEXP_OWNER:
00194                 return (Owner(b->sub1->thing) == Owner(player));
00195         default:
00196                 abort();                                /*
00197                                                                  * bad type 
00198                                                                  */
00199                 return 0;
00200         }
00201 }                                                               /* end eval_boolexp() */

int eval_boolexp_atr ( dbref  player,
dbref  thing,
dbref  from,
char *  key 
)

Definition at line 203 of file boolexp.c.

References eval_boolexp(), free_boolexp(), and parse_boolexp().

Referenced by could_doit(), and eval_boolexp().

00204 {
00205         BOOLEXP *b;
00206         int ret_value;
00207 
00208         b = parse_boolexp(player, key, 1);
00209         if(b == NULL) {
00210                 ret_value = 1;
00211         } else {
00212                 ret_value = eval_boolexp(player, thing, from, b);
00213                 free_boolexp(b);
00214         }
00215         return (ret_value);
00216 }                                                               /* end eval_boolexp_atr() */

BOOLEXP* parse_boolexp ( dbref  player,
const char *  buf,
int  internal 
)

Definition at line 552 of file boolexp.c.

References parse_boolexp_E(), parse_player, parsebuf, parsestore, parsing_internal, StringCopy, and TRUE_BOOLEXP.

Referenced by db_write_object(), debug_examine(), do_decomp(), do_examine(), do_lock(), eval_boolexp_atr(), fun_colorpairs(), fun_elock(), fun_eval(), fun_get(), fun_get_eval(), fun_lock(), fun_pairs(), fun_setlock(), fun_xget(), and view_atr().

00553 {
00554         StringCopy(parsestore, buf);
00555         parsebuf = parsestore;
00556         parse_player = player;
00557         if((buf == NULL) || (*buf == '\0'))
00558                 return (TRUE_BOOLEXP);
00559         parsing_internal = internal;
00560         return parse_boolexp_E();
00561 }                                                               /* end parse_boolexp() */

static BOOLEXP * parse_boolexp_E ( void   )  [static]

Definition at line 530 of file boolexp.c.

References alloc_bool, BOOLEXP_OR, free_boolexp(), OR_TOKEN, parse_boolexp_T(), parsebuf, skip_whitespace(), boolexp::sub1, boolexp::sub2, TRUE_BOOLEXP, and boolexp::type.

Referenced by parse_boolexp(), and parse_boolexp_L().

00531 {
00532         BOOLEXP *b, *b2;
00533 
00534         if((b = parse_boolexp_T()) != TRUE_BOOLEXP) {
00535                 skip_whitespace();
00536                 if(*parsebuf == OR_TOKEN) {
00537                         parsebuf++;
00538 
00539                         b2 = alloc_bool("parse_boolexp_E");
00540                         b2->type = BOOLEXP_OR;
00541                         b2->sub1 = b;
00542                         if((b2->sub2 = parse_boolexp_E()) == TRUE_BOOLEXP) {
00543                                 free_boolexp(b2);
00544                                 return TRUE_BOOLEXP;
00545                         }
00546                         b = b2;
00547                 }
00548         }
00549         return b;
00550 }                                                               /* parse_boolexp_E */

static BOOLEXP* parse_boolexp_F ( void   )  [static]

Definition at line 407 of file boolexp.c.

References alloc_bool, BOOLEXP_ATR, BOOLEXP_CARRY, BOOLEXP_CONST, BOOLEXP_INDIR, BOOLEXP_IS, BOOLEXP_NOT, BOOLEXP_OWNER, CARRY_TOKEN, free_boolexp(), INDIR_TOKEN, IS_TOKEN, NOT_TOKEN, OWNER_TOKEN, parse_boolexp_L(), parsebuf, skip_whitespace(), boolexp::sub1, TRUE_BOOLEXP, and boolexp::type.

Referenced by parse_boolexp_T().

00408 {
00409         BOOLEXP *b2;
00410 
00411         skip_whitespace();
00412         switch (*parsebuf) {
00413         case NOT_TOKEN:
00414                 parsebuf++;
00415                 b2 = alloc_bool("parse_boolexp_F.not");
00416                 b2->type = BOOLEXP_NOT;
00417                 if((b2->sub1 = parse_boolexp_F()) == TRUE_BOOLEXP) {
00418                         free_boolexp(b2);
00419                         return (TRUE_BOOLEXP);
00420                 } else
00421                         return (b2);
00422                 /*
00423                  * NOTREACHED 
00424                  */
00425                 break;
00426         case INDIR_TOKEN:
00427                 parsebuf++;
00428                 b2 = alloc_bool("parse_boolexp_F.indir");
00429                 b2->type = BOOLEXP_INDIR;
00430                 b2->sub1 = parse_boolexp_L();
00431                 if((b2->sub1) == TRUE_BOOLEXP) {
00432                         free_boolexp(b2);
00433                         return (TRUE_BOOLEXP);
00434                 } else if((b2->sub1->type) != BOOLEXP_CONST) {
00435                         free_boolexp(b2);
00436                         return (TRUE_BOOLEXP);
00437                 } else
00438                         return (b2);
00439                 /*
00440                  * NOTREACHED 
00441                  */
00442                 break;
00443         case IS_TOKEN:
00444                 parsebuf++;
00445                 b2 = alloc_bool("parse_boolexp_F.is");
00446                 b2->type = BOOLEXP_IS;
00447                 b2->sub1 = parse_boolexp_L();
00448                 if((b2->sub1) == TRUE_BOOLEXP) {
00449                         free_boolexp(b2);
00450                         return (TRUE_BOOLEXP);
00451                 } else if(((b2->sub1->type) != BOOLEXP_CONST) &&
00452                                   ((b2->sub1->type) != BOOLEXP_ATR)) {
00453                         free_boolexp(b2);
00454                         return (TRUE_BOOLEXP);
00455                 } else
00456                         return (b2);
00457                 /*
00458                  * NOTREACHED 
00459                  */
00460                 break;
00461         case CARRY_TOKEN:
00462                 parsebuf++;
00463                 b2 = alloc_bool("parse_boolexp_F.carry");
00464                 b2->type = BOOLEXP_CARRY;
00465                 b2->sub1 = parse_boolexp_L();
00466                 if((b2->sub1) == TRUE_BOOLEXP) {
00467                         free_boolexp(b2);
00468                         return (TRUE_BOOLEXP);
00469                 } else if(((b2->sub1->type) != BOOLEXP_CONST) &&
00470                                   ((b2->sub1->type) != BOOLEXP_ATR)) {
00471                         free_boolexp(b2);
00472                         return (TRUE_BOOLEXP);
00473                 } else
00474                         return (b2);
00475                 /*
00476                  * NOTREACHED 
00477                  */
00478                 break;
00479         case OWNER_TOKEN:
00480                 parsebuf++;
00481                 b2 = alloc_bool("parse_boolexp_F.owner");
00482                 b2->type = BOOLEXP_OWNER;
00483                 b2->sub1 = parse_boolexp_L();
00484                 if((b2->sub1) == TRUE_BOOLEXP) {
00485                         free_boolexp(b2);
00486                         return (TRUE_BOOLEXP);
00487                 } else if((b2->sub1->type) != BOOLEXP_CONST) {
00488                         free_boolexp(b2);
00489                         return (TRUE_BOOLEXP);
00490                 } else
00491                         return (b2);
00492                 /*
00493                  * NOTREACHED 
00494                  */
00495                 break;
00496         default:
00497                 return (parse_boolexp_L());
00498         }
00499 }                                                               /* end parse_boolexp_F() */

static BOOLEXP* parse_boolexp_L ( void   )  [static]

Definition at line 299 of file boolexp.c.

References alloc_bool, alloc_lbuf, AMBIGUOUS, AND_TOKEN, BOOLEXP_CONST, free_bool, free_boolexp(), free_lbuf, Good_obj, init_match(), MAT_EXIT_PARENTS, match_everything(), match_result(), NOTHING, notify_printf(), OR_TOKEN, parse_boolexp_E(), parse_player, parsebuf, parsing_internal, restore_match_state(), save_match_state(), skip_whitespace(), test_atr(), boolexp::thing, TRUE_BOOLEXP, boolexp::type, and TYPE_THING.

Referenced by parse_boolexp_F().

00300 {
00301         BOOLEXP *b;
00302         char *p, *buf;
00303         MSTATE mstate;
00304 
00305         buf = NULL;
00306         skip_whitespace();
00307 
00308         switch (*parsebuf) {
00309         case '(':
00310                 parsebuf++;
00311                 b = parse_boolexp_E();
00312                 skip_whitespace();
00313                 if(b == TRUE_BOOLEXP || *parsebuf++ != ')') {
00314                         free_boolexp(b);
00315                         return TRUE_BOOLEXP;
00316                 }
00317                 break;
00318         default:
00319 
00320                 /*
00321                  * Must have hit an object ref. Load the name into our  
00322                  * buffer
00323                  */
00324 
00325                 buf = alloc_lbuf("parse_boolexp_L");
00326                 p = buf;
00327                 while (*parsebuf && (*parsebuf != AND_TOKEN) &&
00328                            (*parsebuf != OR_TOKEN) && (*parsebuf != ')')) {
00329                         *p++ = *parsebuf++;
00330                 }
00331 
00332                 /*
00333                  * strip trailing whitespace 
00334                  */
00335 
00336                 *p-- = '\0';
00337                 while (isspace(*p))
00338                         *p-- = '\0';
00339 
00340                 /*
00341                  * check for an attribute 
00342                  */
00343 
00344                 if((b = test_atr(buf)) != NULL) {
00345                         free_lbuf(buf);
00346                         return (b);
00347                 }
00348                 b = alloc_bool("parse_boolexp_L");
00349                 b->type = BOOLEXP_CONST;
00350 
00351                 /*
00352                  * do the match 
00353                  */
00354 
00355                 /*
00356                  * If we are parsing a boolexp that was a stored lock then 
00357                  * we know that object refs are all dbrefs, so we  
00358                  * skip the expensive match code. 
00359                  */
00360 
00361                 if(parsing_internal) {
00362                         if(buf[0] != '#') {
00363                                 free_lbuf(buf);
00364                                 free_bool(b);
00365                                 return TRUE_BOOLEXP;
00366                         }
00367                         b->thing = atoi(&buf[1]);
00368                         if(!Good_obj(b->thing)) {
00369                                 free_lbuf(buf);
00370                                 free_bool(b);
00371                                 return TRUE_BOOLEXP;
00372                         }
00373                 } else {
00374                         save_match_state(&mstate);
00375                         init_match(parse_player, buf, TYPE_THING);
00376                         match_everything(MAT_EXIT_PARENTS);
00377                         b->thing = match_result();
00378                         restore_match_state(&mstate);
00379                 }
00380 
00381                 if(b->thing == NOTHING) {
00382                         notify_printf(parse_player, "I don't see %s here.", buf);
00383                         free_lbuf(buf);
00384                         free_bool(b);
00385                         return TRUE_BOOLEXP;
00386                 }
00387                 if(b->thing == AMBIGUOUS) {
00388                         notify_printf(parse_player, "I don't know which %s you mean!",
00389                                                   buf);
00390                         free_lbuf(buf);
00391                         free_bool(b);
00392                         return TRUE_BOOLEXP;
00393                 }
00394                 free_lbuf(buf);
00395         }
00396         return b;
00397 }                                                               /* end parse_boolexp_L() */

static BOOLEXP* parse_boolexp_T ( void   )  [static]

Definition at line 505 of file boolexp.c.

References alloc_bool, AND_TOKEN, BOOLEXP_AND, free_boolexp(), parse_boolexp_F(), parsebuf, skip_whitespace(), boolexp::sub1, boolexp::sub2, TRUE_BOOLEXP, and boolexp::type.

Referenced by parse_boolexp_E().

00506 {
00507         BOOLEXP *b, *b2;
00508 
00509         if((b = parse_boolexp_F()) != TRUE_BOOLEXP) {
00510                 skip_whitespace();
00511                 if(*parsebuf == AND_TOKEN) {
00512                         parsebuf++;
00513 
00514                         b2 = alloc_bool("parse_boolexp_T");
00515                         b2->type = BOOLEXP_AND;
00516                         b2->sub1 = b;
00517                         if((b2->sub2 = parse_boolexp_T()) == TRUE_BOOLEXP) {
00518                                 free_boolexp(b2);
00519                                 return TRUE_BOOLEXP;
00520                         }
00521                         b = b2;
00522                 }
00523         }
00524         return b;
00525 }                                                               /* end parse_boolexp_T() */

static void skip_whitespace ( void   )  [static]

Definition at line 230 of file boolexp.c.

References parsebuf.

Referenced by parse_boolexp_E(), parse_boolexp_F(), parse_boolexp_L(), and parse_boolexp_T().

00231 {
00232         while (*parsebuf && isspace(*parsebuf))
00233                 parsebuf++;
00234 }

static BOOLEXP* test_atr ( char *  s  )  [static]

Definition at line 238 of file boolexp.c.

References alloc_bool, alloc_lbuf, atr_str(), BOOLEXP_ATR, BOOLEXP_EVAL, free_lbuf, God, attr::number, parse_player, StringCopy, strsave(), boolexp::sub1, boolexp::thing, and boolexp::type.

Referenced by parse_boolexp_L().

00239 {
00240         ATTR *attrib;
00241         BOOLEXP *b;
00242         char *buff, *s1;
00243         int anum, locktype;
00244 
00245         buff = alloc_lbuf("test_atr");
00246         StringCopy(buff, s);
00247         for(s = buff; *s && (*s != ':') && (*s != '/'); s++);
00248         if(!*s) {
00249                 free_lbuf(buff);
00250                 return ((BOOLEXP *) NULL);
00251         }
00252         if(*s == '/')
00253                 locktype = BOOLEXP_EVAL;
00254         else
00255                 locktype = BOOLEXP_ATR;
00256 
00257         *s++ = '\0';
00258         /*
00259          * see if left side is valid attribute.  Access to attr is checked on 
00260          * 
00261          * *  * *  * *  * *  * * eval * Also allow numeric references to *
00262          * attributes. * It * can't * hurt  * us, and * lets us import stuff
00263          * * that stores * attr * locks by * number * instead of by * name. 
00264          */
00265         if(!(attrib = atr_str(buff))) {
00266 
00267                 /*
00268                  * Only #1 can lock on numbers 
00269                  */
00270                 if(!God(parse_player)) {
00271                         free_lbuf(buff);
00272                         return ((BOOLEXP *) NULL);
00273                 }
00274                 s1 = buff;
00275                 for(s1 = buff; isdigit(*s1); s1++);
00276                 if(*s1) {
00277                         free_lbuf(buff);
00278                         return ((BOOLEXP *) NULL);
00279                 }
00280                 anum = atoi(buff);
00281         } else {
00282                 anum = attrib->number;
00283         }
00284 
00285         /*
00286          * made it now make the parse tree node 
00287          */
00288         b = alloc_bool("test_str");
00289         b->type = locktype;
00290         b->thing = (dbref) anum;
00291         b->sub1 = (BOOLEXP *) strsave(s);
00292         free_lbuf(buff);
00293         return (b);
00294 }                                                               /* end test_atr() */


Variable Documentation

dbref parse_player [static]

Definition at line 228 of file boolexp.c.

Referenced by parse_boolexp(), parse_boolexp_L(), and test_atr().

const char* parsebuf [static]

Definition at line 226 of file boolexp.c.

Referenced by parse_boolexp(), parse_boolexp_E(), parse_boolexp_F(), parse_boolexp_L(), parse_boolexp_T(), and skip_whitespace().

char parsestore[LBUF_SIZE] [static]

Definition at line 227 of file boolexp.c.

Referenced by parse_boolexp().

int parsing_internal = 0 [static]

Definition at line 18 of file boolexp.c.

Referenced by parse_boolexp(), and parse_boolexp_L().


Generated on Mon May 28 04:25:26 2007 for BattletechMUX by  doxygen 1.4.7