This is patch39 to PennMUSH 1.7.7. After applying this patch, you will have version 1.7.7p39 To apply this patch, save it to a file in your top-level MUSH directory, and do the following: patch -p1 < 1.7.7-patch39 make clean make install If you use GNU patch 2.2, you probably want the above to be 'patch -b -p1', not just 'patch -p1'. Unix (or cygwin) users need not worry about failed hunks in src/switchinc.c, hdrs/switches.h, hdrs/cmds.h, or hdrs/funs.h. These files are automatically rebuilt on compile. On the off chance they appear not to be, simply rm them and re-run make. Then @shutdown and restart your MUSH. - Alan/Javelin In this patch: Major Changes: * Game and chat database formats have been rewritten. They are much more human-readable, can be extended with new fields without using versioning flags, and provide better detection and reporting of malformed databases. [SW] * Chunk deref counts for locks are now stored in the database. [SW] Commands: * New 'buy' command for purchasing items from vendors that can offer multiple items at multiple prices. Patch by Walker@M*U*S*H. * restrict_command and @command/restrict can now include an error message to be sent when the player can't use the command, which supercedes more generic errors. Suggested by Philip Mak. Patch by Walker@M*U*S*H. Functions: * lwho() can take an argument to produce the who list from that player's viewpoint. Patch by Walker@M*U*S*H. Fixes: * nattr(obj/attrib) returns 1 when matching a non-wildcarded attrib. Report by Impster@M*U*S*H. * +chan is now converted to @chat = (with noeval) so @chat hooks apply to +chatting too. Patch by Walker@M*U*S*H. * You must be able to locate a player to perform elock() on them. Report by Ambrosia. * Help fixes by Sketch@M*U*S*H. * Simplification of @version code. [SW] * cemit() restrictions are now based on those of @cemit, instead of @emit. Report by BlackPhyr. * Setting queue_loss to 0 disables queue_loss. A bad idea, but more consistent behavior. Suggested by K Moon. * Examining objects always shows their actual number of coins, whether or not they're admin or no_pay. * Code cleanup in @edit and in char routines. [SW]. * Wrong object checked when reporting money as unlimited. Report by Nate Barney. [EEH] * New hints/freebsd_5.sh. Suggested by James Lang. * INFO command once again reports the server as "PennMUSH", not just a version number. Report by Mark Hassman. * Win32 linting. Builds with NT_TCP should work again (although @shutdown/reboot under NT_TCP is still not functional). Reorganization of the Win32 services macros. [EEH] * Fix to bug with login attempts using literal encrypted strings. Reported by Cadar and Mirrador. * @ps/all shows the right label on top. Patch by qa'toq@bDv. Prereq: 1.7.7p38 *** 1_7_7.1196/Patchlevel Wed, 25 Aug 2004 20:45:08 -0500 dunemush (pennmush/5_Patchlevel 1.17.1.11.1.40 600) --- 1_7_7.1227(w)/Patchlevel Mon, 25 Oct 2004 17:41:02 -0500 dunemush (pennmush/5_Patchlevel 1.17.1.11.1.41 600) *************** *** 1,2 **** Do not edit this file. It is maintained by the official PennMUSH patches. ! This is PennMUSH 1.7.7p38 --- 1,2 ---- Do not edit this file. It is maintained by the official PennMUSH patches. ! This is PennMUSH 1.7.7p39 *** 1_7_7.1196/CHANGES.177 Wed, 25 Aug 2004 20:45:08 -0500 dunemush (pennmush/g/23_CHANGES 1.48.1.258.1.14.1.191 600) --- 1_7_7.1227(w)/CHANGES.177 Mon, 25 Oct 2004 17:40:46 -0500 dunemush (pennmush/g/23_CHANGES 1.48.1.258.1.14.1.212 600) *************** *** 18,23 **** --- 18,70 ---- ========================================================================== + Version 1.7.7 patchlevel 39 October 25, 2004 + + Major Changes: + * Game and chat database formats have been rewritten. They are + much more human-readable, can be extended with new fields + without using versioning flags, and provide better detection + and reporting of malformed databases. [SW] + * Chunk deref counts for locks are now stored in the database. [SW] + Commands: + * New 'buy' command for purchasing items from vendors that can offer + multiple items at multiple prices. Patch by Walker@M*U*S*H. + * restrict_command and @command/restrict can now include an + error message to be sent when the player can't use the command, + which supercedes more generic errors. Suggested by Philip Mak. + Patch by Walker@M*U*S*H. + Functions: + * lwho() can take an argument to produce the who list from that + player's viewpoint. Patch by Walker@M*U*S*H. + Fixes: + * nattr(obj/attrib) returns 1 when matching a non-wildcarded attrib. + Report by Impster@M*U*S*H. + * +chan is now converted to @chat = (with noeval) + so @chat hooks apply to +chatting too. Patch by Walker@M*U*S*H. + * You must be able to locate a player to perform elock() on them. + Report by Ambrosia. + * Help fixes by Sketch@M*U*S*H. + * Simplification of @version code. [SW] + * cemit() restrictions are now based on those of @cemit, instead + of @emit. Report by BlackPhyr. + * Setting queue_loss to 0 disables queue_loss. A bad idea, but + more consistent behavior. Suggested by K Moon. + * Examining objects always shows their actual number of coins, + whether or not they're admin or no_pay. + * Code cleanup in @edit and in char routines. [SW]. + * Wrong object checked when reporting money as unlimited. Report + by Nate Barney. [EEH] + * New hints/freebsd_5.sh. Suggested by James Lang. + * INFO command once again reports the server as "PennMUSH", + not just a version number. Report by Mark Hassman. + * Win32 linting. Builds with NT_TCP should work again (although + @shutdown/reboot under NT_TCP is still not functional). + Reorganization of the Win32 services macros. [EEH] + * Fix to bug with login attempts using literal encrypted strings. + Reported by Cadar and Mirrador. + * @ps/all shows the right label on top. Patch by qa'toq@bDv. + + Version 1.7.7 patchlevel 38 August 25, 2004 Commands: *** 1_7_7.1196/game/txt/hlp/penntop.hlp Mon, 23 Aug 2004 15:55:05 -0500 dunemush (pennmush/13_penntop.hl 1.2.1.27.1.3.1.2.1.2.1.1.1.1.1.1.1.1.1.12.1.1.1.1.1.8.1.11.1.1.1.1 600) --- 1_7_7.1227(w)/game/txt/hlp/penntop.hlp Sat, 09 Oct 2004 15:30:52 -0500 dunemush (pennmush/13_penntop.hl 1.2.1.27.1.3.1.2.1.2.1.1.1.1.1.1.1.1.1.12.1.1.1.1.1.8.1.11.1.1.1.2 600) *************** *** 1917,1928 **** and @function. In the config file, the syntax is: ! restrict_command command-name restriction restrict_function function-name restriction From the game: ! @command/restrict command-name=restriction @function/restrict function-name=restriction (Continued in restrict2) & RESTRICT2 --- 1917,1931 ---- and @function. In the config file, the syntax is: ! restrict_command command-name restriction [" ] restrict_function function-name restriction From the game: ! @command/restrict command-name=restriction [" ] @function/restrict function-name=restriction + + For commands, if is given, that message is sent to the + player who runs it instead of a generic, unhelpful error message. (Continued in restrict2) & RESTRICT2 *** 1_7_7.1196/game/txt/hlp/pennfunc.hlp Thu, 12 Aug 2004 12:07:04 -0500 dunemush (pennmush/16_pennfunc.h 1.2.1.50.1.1.1.1.1.2.1.7.1.8.1.1.1.1.1.1.1.1.1.1.1.1.1.3.1.1.1.1.1.1.1.1.1.1.1.1.1.9.1.1.1.1.1.3.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.21 600) --- 1_7_7.1227(w)/game/txt/hlp/pennfunc.hlp Mon, 25 Oct 2004 17:30:39 -0500 dunemush (pennmush/16_pennfunc.h 1.2.1.50.1.1.1.1.1.2.1.7.1.8.1.1.1.1.1.1.1.1.1.1.1.1.1.3.1.1.1.1.1.1.1.1.1.1.1.1.1.9.1.1.1.1.1.3.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.23 600) *************** *** 176,181 **** --- 176,182 ---- These functions operate only on integers (if passed floating point numbers, they will return an error or misbehave): dec() div() floordiv() inc() mod() + remainder() These functions operate on n-dimensional vectors. A vector is a delimiter-separated list of numbers (space-separated, by default): *************** *** 587,592 **** --- 588,595 ---- . If it's lower than the lower bound, the lower bound is returned. If it's higher than the higher bound, the higher bound is returned. + + See also: ceil(), floor(), round(), trunc() & BXOR() bxor(, ,...) *************** *** 608,613 **** --- 611,618 ---- ceil() Returns the least integral value greater than or equal to . + + See also: floor(), bound(), round(), trunc() & CEMIT() cemit(, [, ]) *************** *** 1329,1334 **** --- 1334,1341 ---- floor() Returns the greatest integral value less than or equal to . + + See also: ceil(), bound(), round(), trunc() & FMOD() fmod(,) *************** *** 2324,2334 **** --- 2331,2346 ---- function. & LWHO() lwho() + lwho() This returns a list of the dbref numbers for all currently-connected players. When mortals use this function, the dbref numbers of DARK wizards or royalty do NOT appear on the dbref list. + If lwho() is given an argument, and used by an object that can see + DARK and Hidden players, lwho() returns the output of lwho() from + 's point of view. + See also: mwho(), nwho(), xwho() & MAIL() mail() *************** *** 2467,2477 **** & MEAN() mean(,...) ! Returns the mean (Average) of its arguments. & MEDIAN() median(,...) Returns the median (the middlemost numerically) of its arguments. & MEMBER() member(,[,]) --- 2479,2493 ---- & MEAN() mean(,...) ! Returns the mean (arithmetic average) of its arguments. ! ! See also: median(), stddev() & MEDIAN() median(,...) Returns the median (the middlemost numerically) of its arguments. + + See also: mean(), stddev() & MEMBER() member(,[,]) *************** *** 3214,3219 **** --- 3230,3236 ---- Rounds to decimal places. must be between 0 and 6. + See also: ceil(), floor(), bound(), trunc() & S() & S-FUNCTION s(string) *************** *** 3673,3678 **** --- 3690,3697 ---- stddev(,...) Returns the sample standard deviation of its arguments. + + See also: mean(), median() & STRCAT() strcat(, ) *************** *** 4066,4071 **** --- 4085,4091 ---- also be used to return the leading numeric prefix of a string, or "0" if there isn't one. For example, "val(101Dalmations)" => 101. + See also: ceil(), floor(), bound(), round() & TYPE() type() *** 1_7_7.1196/game/txt/hlp/penncmd.hlp Tue, 24 Aug 2004 09:41:40 -0500 dunemush (pennmush/18_penncmd.hl 1.2.1.1.1.47.1.1.1.1.1.3.1.4.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.2.1.10.1.1.1.1.1.1.1.1.1.1.1.44 600) --- 1_7_7.1227(w)/game/txt/hlp/penncmd.hlp Sat, 09 Oct 2004 15:41:13 -0500 dunemush (pennmush/18_penncmd.hl 1.2.1.1.1.47.1.1.1.1.1.3.1.4.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.2.1.10.1.1.1.1.1.1.1.1.1.1.1.45 600) *************** *** 3745,3750 **** --- 3745,3812 ---- ability to take an object in someone else's inventory. See also: @lock, ENTER_OK, give, drop, @success, inventory + & @abuy + @abuy = + + Sets the actions to be taken after a player buys an item + from PRICELIST. The item purchased is passed in as %0, + and the amount paid as %1 + + See also: buy, @buy, @obuy, @pricelist, MONEY, ACTION LISTS + & @buy + @buy [=] + + Sets the message that is shown to anyone who buys something from + the object, using the 'buy' command. The item purchased is passed + in as %0, and the amount paid as %1. + + See also: buy, @abuy, @obuy, @pricelist, MONEY + & @obuy + @obuy [=] + + Sets the message that will be show to others whenever someone buys + an item from the object's PRICELIST using the 'buy' command. The + name of the person giving the money will be automatically inserted at + the beginning of the message. The item purchased is passed in as %0, + and the amount paid as %1. + + See also: buy, @abuy, @obuy, @pricelist, MONEY + & @pricelist + @pricelist =:[,][ :...] + + The PRICELIST attribute is a space-delimited list of item names + and prices that are checked when the 'buy' command is run. + + An item name may have '_'s where the player would use a space in + the name. + + A price is either a number (20), a range of numbers (10-30), or + a minimum number (10+). + + ex: + @PRICELIST vendor=mansion:1000+ large_house:100-200 house:20,30,50 + + See also: buy, @abuy, @buy, @obuy, MONEY + & buy + buy [ from ][ for ] + + When you try buying an item, PRICELIST attributes on nearby objects + (or if given) will be checked for matching item:costs. If + is given, the first item that matches that cost will be purchased. + Otherwise, the first matching item that you can afford will be purchased. + + If the pricelist match contains a list of prices, + ITEM:30,20,10, the first one you can afford will be the resulting price. + + ex: + > &PRICELIST vendor=coke:20 pepsi:20 + > &drink.coke vendor=You enjoy a delicious coke. + > &drink.pepsi vendor=It tastes like a funny coke. + > @BUY vendor=u(drink.%0) + > buy coke + You enjoy a delicious coke. + + See also: @ABUY, @BUY, @PRICELIST & give give[/silent] = give[/silent] to *** 1_7_7.1196/game/mushcnf.dst Thu, 15 Jul 2004 14:37:11 -0500 dunemush (pennmush/41_mushcnf.ds 1.1.1.19.1.1.1.2.1.1.1.8.1.1.1.1.1.32 600) --- 1_7_7.1227(w)/game/mushcnf.dst Sat, 09 Oct 2004 15:31:50 -0500 dunemush (pennmush/41_mushcnf.ds 1.1.1.19.1.1.1.2.1.1.1.8.1.1.1.1.1.34 600) *************** *** 260,274 **** # the maximum number of functions that can be invoked function_invocation_limit 2500 ! # the maximum number of times we're allowed to recursively call the parser # for a single expression. This limits how much the stack size can increase, # which could be useful if your host limits your stack (it will prevent # a crash). The higher your allowed stack size limit, the larger the # mush process can grow, and the higher this can be set. Generally # speaking, you won't ever see more than 8192 recursions, so that's # probably an upper limit, but most sane code shouldn't need more ! # than a couple thousand. Setting it to '0' means unlimited. ! call_limit 5000 # The maximum number of milliseconds of CPU time that a single queue entry # is allowed to use before aborting. Setting this to a low number will --- 260,274 ---- # the maximum number of functions that can be invoked function_invocation_limit 2500 ! # the maximum depth we're allowed to recursively call the parser # for a single expression. This limits how much the stack size can increase, # which could be useful if your host limits your stack (it will prevent # a crash). The higher your allowed stack size limit, the larger the # mush process can grow, and the higher this can be set. Generally # speaking, you won't ever see more than 8192 recursions, so that's # probably an upper limit, but most sane code shouldn't need more ! # than a couple hundred. Setting it to '0' means unlimited. ! call_limit 100 # The maximum number of milliseconds of CPU time that a single queue entry # is allowed to use before aborting. Setting this to a low number will *************** *** 341,347 **** queue_cost 10 # One out of how many commands that are queued will cost the ! # player a coin? queue_loss 63 # What does it cost to build various things? --- 341,349 ---- queue_cost 10 # One out of how many commands that are queued will cost the ! # player a coin? Setting this to 1 causes a coin to be lost with ! # every command. Setting it to 0 disables coin loss for queued ! # commands (and is a very bad idea). queue_loss 63 # What does it cost to build various things? *** 1_7_7.1196/src/local.dst Sat, 10 Jul 2004 09:53:09 -0500 dunemush (pennmush/b/19_local.dst 1.21 660) --- 1_7_7.1227(w)/src/local.dst Tue, 02 Nov 2004 11:00:10 -0600 dunemush (pennmush/b/19_local.dst 1.22 660) *************** *** 10,17 **** #include "copyrite.h" #include "config.h" #include - #include #include "conf.h" #include "externs.h" #include "parse.h" #include "htab.h" --- 10,17 ---- #include "copyrite.h" #include "config.h" #include #include "conf.h" + #include "dbio.h" #include "externs.h" #include "parse.h" #include "htab.h" *************** *** 19,27 **** #include "confmagic.h" extern HASHTAB htab_reserved_aliases; - - extern jmp_buf db_err; - #define OUTPUT(fun) do { if ((fun) < 0) longjmp(db_err, 1); } while (0) /* Called after all MUSH init is done. */ --- 19,24 ---- *** 1_7_7.1196/src/warnings.c Thu, 27 May 2004 14:05:53 -0500 dunemush (pennmush/b/25_warnings.c 1.21.1.1.1.8 660) --- 1_7_7.1227(w)/src/warnings.c Tue, 02 Nov 2004 11:00:10 -0600 dunemush (pennmush/b/25_warnings.c 1.21.1.1.1.9 660) *************** *** 56,63 **** /** All warnings */ #define W_ALL (W_EXTRA|W_EXIT_DESC) - /** The type that stores the warning bitmask */ - typedef long int warn_type; /** A structure representing a topology warning check. */ typedef struct a_tcheck { --- 56,61 ---- *************** *** 282,292 **** do_warnings(dbref player, const char *name, const char *warns) { dbref thing; - int found = 0; - warn_type flags, negate_flags; - char tbuf1[BUFFER_LEN]; - char *w, *s; - tcheck *c; switch (thing = match_result(player, name, NOTYPE, MAT_EVERYTHING)) { case NOTHING: --- 280,285 ---- *************** *** 307,316 **** break; } flags = W_NONE; negate_flags = W_NONE; ! if (warns && *warns) { ! strcpy(tbuf1, warns); /* Loop through whatever's listed and add on those warnings */ s = trim_space_sep(tbuf1, ' '); w = split_token(&s, ' '); --- 300,328 ---- break; } + Warnings(thing) = parse_warnings(player, warns); + notify_format(player, T("@warnings set to %s"), + unparse_warnings(Warnings(thing))); + } + + /** Given a list of warnings, return the bitmask that represents it. + * \param player dbref to report errors to, or NOTHING. + * \param warnings the string of warning names + * \return a warning bitmask + */ + warn_type + parse_warnings(dbref player, const char *warnings) + { + int found = 0; + warn_type flags, negate_flags; + char tbuf1[BUFFER_LEN]; + char *w, *s; + tcheck *c; + flags = W_NONE; negate_flags = W_NONE; ! if (warnings && *warnings) { ! strcpy(tbuf1, warnings); /* Loop through whatever's listed and add on those warnings */ s = trim_space_sep(tbuf1, ' '); w = split_token(&s, ' '); *************** *** 334,370 **** } } /* At this point, we haven't matched any warnings. */ ! if (!found) { notify_format(player, T("Unknown warning: %s"), w); } w = split_token(&s, ' '); } ! if (flags || !negate_flags) { ! Warnings(thing) = (flags & ~negate_flags); ! } else { ! Warnings(thing) &= ~negate_flags; ! } ! notify_format(player, T("@warnings set to %s"), unparse_warnings(thing)); ! return; ! } } ! ! /** Given an object, return a string of warnings on it. ! * \param thing dbref of object. * \return pointer to statically allocated string listing warnings. */ const char * ! unparse_warnings(dbref thing) { static char tbuf1[BUFFER_LEN]; ! int warns, listsize, indexx; ! warn_type the_flag; ! ! warns = Warnings(thing); ! ! if (!warns) ! return "none"; tbuf1[0] = '\0'; --- 346,370 ---- } } /* At this point, we haven't matched any warnings. */ ! if (!found && player != NOTHING) { notify_format(player, T("Unknown warning: %s"), w); } w = split_token(&s, ' '); } ! return flags & ~negate_flags; ! } else ! return 0; } ! /** Given a warning bitmask, return a string of warnings on it. ! * \param warns the warnings. * \return pointer to statically allocated string listing warnings. */ const char * ! unparse_warnings(warn_type warns) { static char tbuf1[BUFFER_LEN]; ! int listsize, indexx; tbuf1[0] = '\0'; *************** *** 373,379 **** /* Point c at last non-null in checklist, and go backwards */ for (indexx = listsize - 2; warns && (indexx >= 0); indexx--) { ! the_flag = checklist[indexx].flag; if (!(the_flag & ~warns)) { /* Which is to say: * if the bits set on the_flag is a subset of the bits set on warns --- 373,379 ---- /* Point c at last non-null in checklist, and go backwards */ for (indexx = listsize - 2; warns && (indexx >= 0); indexx--) { ! warn_type the_flag = checklist[indexx].flag; if (!(the_flag & ~warns)) { /* Which is to say: * if the bits set on the_flag is a subset of the bits set on warns *** 1_7_7.1196/src/version.c Tue, 29 Jun 2004 19:37:09 -0500 dunemush (pennmush/b/26_version.c 1.11 660) --- 1_7_7.1227(w)/src/version.c Tue, 02 Nov 2004 11:00:10 -0600 dunemush (pennmush/b/26_version.c 1.13 660) *************** *** 11,21 **** */ #include "config.h" #include "copyrite.h" - - #include - #include #include "conf.h" - #include "externs.h" #include "version.h" #include "patches.h" --- 11,17 ---- *************** *** 32,45 **** void do_version(dbref player) { - char buff[BUFFER_LEN]; notify_format(player, T("You are connected to %s"), MUDNAME); ! ! strcpy(buff, ctime(&globals.start_time)); ! buff[strlen(buff) - 1] = '\0'; /* eat the newline */ ! notify_format(player, T("Last restarted: %s"), buff); ! notify_format(player, "PennMUSH version %s patchlevel %s %s", VERSION, PATCHLEVEL, PATCHDATE); #ifdef PATCHES --- 28,37 ---- void do_version(dbref player) { notify_format(player, T("You are connected to %s"), MUDNAME); ! notify_format(player, T("Last restarted: %s"), ! show_time(globals.start_time, 0)); notify_format(player, "PennMUSH version %s patchlevel %s %s", VERSION, PATCHLEVEL, PATCHDATE); #ifdef PATCHES *** 1_7_7.1196/src/utils.c Sat, 10 Jul 2004 09:53:09 -0500 dunemush (pennmush/b/27_utils.c 1.30.1.1.1.22 660) --- 1_7_7.1227(w)/src/utils.c Tue, 02 Nov 2004 11:00:10 -0600 dunemush (pennmush/b/27_utils.c 1.30.1.1.1.23 660) *************** *** 142,148 **** AL_CREATOR(*attrib) = player; AL_NAME(*attrib) = strdup("#lambda"); t = compress(str); ! (*attrib)->data = chunk_create(t, u_strlen(t), 0); AL_FLAGS(*attrib) = AF_ANON; AL_NEXT(*attrib) = NULL; *thing = player; --- 142,148 ---- AL_CREATOR(*attrib) = player; AL_NAME(*attrib) = strdup("#lambda"); t = compress(str); ! (*attrib)->data = chunk_create(t, (u_int_16) u_strlen(t), 0); AL_FLAGS(*attrib) = AF_ANON; AL_NEXT(*attrib) = NULL; *thing = player; *** 1_7_7.1196/src/set.c Fri, 06 Aug 2004 09:38:25 -0500 dunemush (pennmush/b/38_set.c 1.26.1.5.1.1.2.1.1.1.1.1.1.11.1.1.1.1.1.1.1.1.1.1.1.1.1.39 660) --- 1_7_7.1227(w)/src/set.c Tue, 02 Nov 2004 11:00:10 -0600 dunemush (pennmush/b/38_set.c 1.26.1.5.1.1.2.1.1.1.1.1.1.11.1.1.1.1.1.1.1.1.1.1.1.1.1.41 660) *************** *** 36,55 **** #include "game.h" #include "confmagic.h" - void do_name(dbref player, const char *name, char *newname); - void do_chown(dbref player, const char *name, const char *newobj, int preserve); static int chown_ok(dbref player, dbref thing, dbref newowner); - int do_chzone(dbref player, const char *name, const char *newobj, int noisy); void do_attrib_flags (dbref player, const char *obj, const char *atrname, const char *flag); - int do_set(dbref player, const char *name, char *flag); - void do_cpattr - (dbref player, char *oldpair, char **newpair, int move, int noflagcopy); - void do_gedit(dbref player, char *it, char **argv, enum edit_type target); - void do_trigger(dbref player, char *object, char **argv); - void do_use(dbref player, const char *what); - void do_parent(dbref player, char *name, char *parent_name); - void do_wipe(dbref player, char *name); static int af_helper(dbref player, dbref thing, dbref parent, char const *pattern, ATTR *atr, void *args); static int gedit_helper(dbref player, dbref thing, dbref parent, --- 36,44 ---- *************** *** 748,753 **** --- 737,749 ---- return; } + /** Argument struct for gedit_helper */ + struct gedit_args { + enum edit_type target; /**< The type of edit */ + char *from; /**< What is going to be replaced? */ + char *to; /**< What it gets replaced with. */ + }; + static int gedit_helper(dbref player, dbref thing, dbref parent __attribute__ ((__unused__)), *************** *** 759,773 **** char *s, *val; char tbuf1[BUFFER_LEN], tbuf_ansi[BUFFER_LEN]; char *tbufp, *tbufap; - char **argv = (char **) args; size_t rlen, vlen; ! enum edit_type target; ! val = argv[1]; vlen = strlen(val); ! r = argv[2] ? argv[2] : ""; rlen = strlen(r); - target = (enum edit_type) argv[3]; /* Nasty kludge, getting enum passed as address */ tbufp = tbuf1; tbufap = tbuf_ansi; --- 755,769 ---- char *s, *val; char tbuf1[BUFFER_LEN], tbuf_ansi[BUFFER_LEN]; char *tbufp, *tbufap; size_t rlen, vlen; ! struct gedit_args *gargs; ! ! gargs = args; ! val = gargs->from; vlen = strlen(val); ! r = gargs->to ? gargs->to : ""; rlen = strlen(r); tbufp = tbuf1; tbufap = tbuf_ansi; *************** *** 808,814 **** /* Add one at the start */ if (!safe_strl(r, rlen, tbuf1, &tbufp)) { ! if (target != EDIT_FIRST) { for (last = 0; last < haystack->len; last++) { /* Add the next character */ if (safe_ansi_string(haystack, last, 1, tbuf1, &tbufp)) { --- 804,810 ---- /* Add one at the start */ if (!safe_strl(r, rlen, tbuf1, &tbufp)) { ! if (gargs->target != EDIT_FIRST) { for (last = 0; last < haystack->len; last++) { /* Add the next character */ if (safe_ansi_string(haystack, last, 1, tbuf1, &tbufp)) { *************** *** 866,872 **** ansi_long_flag = 1; } last = p - haystack->text + vlen; ! if (target == EDIT_FIRST) break; } if (last < haystack->len && !too_long) { --- 862,868 ---- ansi_long_flag = 1; } last = p - haystack->text + vlen; ! if (gargs->target == EDIT_FIRST) break; } if (last < haystack->len && !too_long) { *************** *** 907,912 **** --- 903,909 ---- dbref thing; char tbuf1[BUFFER_LEN]; char *q; + struct gedit_args args; if (!(it && *it)) { notify(player, T("I need to know what you want to edit.")); *************** *** 930,937 **** notify(player, T("Nothing to do.")); return; } ! argv[3] = (char *) target; /* Nasty kludge, passing an enum as an address */ ! if (!atr_iter_get(player, thing, q, 0, gedit_helper, argv)) notify(player, T("No matching attributes.")); } --- 927,936 ---- notify(player, T("Nothing to do.")); return; } ! args.from = argv[1]; ! args.to = argv[2]; ! args.target = target; ! if (!atr_iter_get(player, thing, q, 0, gedit_helper, &args)) notify(player, T("No matching attributes.")); } *** 1_7_7.1196/src/services.c Tue, 02 Mar 2004 17:35:59 -0600 dunemush (pennmush/b/39_services.c 1.17 660) --- 1_7_7.1227(w)/src/services.c Tue, 02 Nov 2004 11:00:10 -0600 dunemush (pennmush/b/39_services.c 1.18 660) *************** *** 3,9 **** /* Author: Nick Gammon */ #ifdef WIN32 - #ifndef __MINGW32__ #include "copyrite.h" #include "config.h" --- 3,8 ---- *************** *** 22,27 **** --- 21,28 ---- #include "mymalloc.h" #include "confmagic.h" + #ifdef WIN32SERVICES + #define THIS_SERVICE "PennMUSH" #define THIS_SERVICE_DISPLAY "PennMUSH for Win32" *************** *** 829,833 **** } /* end of convert_error */ ! #endif /* ! __MINGW32__ */ #endif /* WIN32 */ --- 830,834 ---- } /* end of convert_error */ ! #endif /* WIN32SERVICES */ #endif /* WIN32 */ *** 1_7_7.1196/src/rob.c Wed, 30 Jun 2004 15:00:16 -0500 dunemush (pennmush/b/42_rob.c 1.18.1.2.1.3.1.3.1.32 660) --- 1_7_7.1227(w)/src/rob.c Tue, 02 Nov 2004 11:00:10 -0600 dunemush (pennmush/b/42_rob.c 1.18.1.2.1.3.1.3.1.35 660) *************** *** 13,18 **** --- 13,19 ---- #include "copyrite.h" #include #include + #include #include "conf.h" #include "externs.h" #include "mushdb.h" *************** *** 25,30 **** --- 26,32 ---- #include "dbdefs.h" #include "game.h" #include "confmagic.h" + #include "case.h" static void do_give_to(dbref player, char *arg, int silent); *************** *** 143,148 **** --- 145,329 ---- } break; } + } + } + + /** the buy command + * \param player the enactor/buyer + * \param item the item to buy + * \param from who to buy it from + * \param cost the cost + */ + void + do_buy(dbref player, char *item, char *from, int price) + { + dbref vendor; + char *prices; + char *plus; + char *cost; + char finditem[BUFFER_LEN]; + char buycost[BUFFER_LEN]; + int boughtit; + int len; + char buff[BUFFER_LEN], *bp; + char obuff[BUFFER_LEN]; + char *r[BUFFER_LEN / 2]; + char *c[BUFFER_LEN / 2]; + char *buy_env[10] = { NULL }; + int affordable; + int costcount, ci; + int count, i; + int low, high; /* lower bound, upper bound of cost */ + ATTR *a; + + if (!GoodObject(Location(player))) + return; + + vendor = Contents(Location(player)); + if (vendor == player) + vendor = Next(player); + + if (from != NULL && *from) { + switch (vendor = + match_result(player, from, TYPE_PLAYER, + MAT_NEAR_THINGS | MAT_ENGLISH)) { + case NOTHING: + notify(player, T("Buy from whom?")); + return; + case AMBIGUOUS: + notify(player, T("I don't know who you mean!")); + return; + } + if (vendor == player) { + notify(player, T("You can't buy from yourself!")); + return; + } + } else if (vendor == NOTHING) { + notify(player, T("There's nobody here to buy things from.")); + return; + } else { + from = NULL; + } + + if (!item || !*item || !(item = trim_space_sep(item, ' '))) { + notify(player, T("Buy what?")); + return; + } + + bp = finditem; + safe_str(item, finditem, &bp); + safe_chr(':', finditem, &bp); + *bp = '\0'; + for (bp = strchr(finditem, ' '); bp; bp = strchr(bp, ' ')) + *bp = '_'; + + len = strlen(finditem); + + /* Scan pricelists */ + boughtit = -1; + affordable = 1; + do { + a = atr_get(vendor, "PRICELIST"); + if (!a) + continue; + /* atr_value uses a static buffer, so we'll take advantage of that */ + prices = atr_value(a); + upcasestr(prices); + count = list2arr(r, BUFFER_LEN / 2, atr_value(a), ' '); + if (!count) + continue; + for (i = 0; i < count; i++) { + if (!strncasecmp(finditem, r[i], len)) { + /* Check cost */ + cost = r[i] + len; + if (!*cost) + continue; + costcount = list2arr(c, BUFFER_LEN / 2, cost, ','); + for (ci = 0; ci < costcount; ci++) { + cost = c[ci]; + /* Formats: + * 10,2000+,10-100 + */ + if ((plus = strchr(cost, '-'))) { + *(plus++) = '\0'; + if (!is_strict_integer(cost)) + continue; + if (!is_strict_integer(plus)) + continue; + low = parse_integer(cost); + high = parse_integer(plus); + if (price < 0) { + boughtit = low; + } else if (price >= low && price <= high) { + boughtit = price; + } + } else if ((plus = strchr(cost, '+'))) { + *(plus++) = '\0'; + if (!is_strict_integer(cost)) + continue; + low = parse_integer(cost); + if (price < 0) { + boughtit = low; + } else if (price > low) { + boughtit = price; + } + } else if (is_strict_integer(cost)) { + low = parse_integer(cost); + if (price < 0) { + boughtit = low; + } else if (low == price) { + boughtit = price; + } + } else { + continue; + } + if (boughtit >= 0) { + if (!payfor(player, boughtit)) { + affordable = 0; + boughtit = 0; + continue; + } + bp = strchr(finditem, ':'); + if (bp) + *bp = '\0'; + for (bp = finditem; *bp; bp++) + *bp = DOWNCASE(*bp); + bp = buff; + safe_format(buff, &bp, "You buy a %s from %s.", + finditem, Name(vendor)); + *bp = '\0'; + bp = obuff; + safe_format(obuff, &bp, "buys a %s from %s.", + finditem, Name(vendor)); + buy_env[0] = finditem; + buy_env[1] = buycost; + bp = buycost; + safe_integer(boughtit, buycost, &bp); + *bp = '\0'; + real_did_it(player, vendor, "BUY", buff, "OBUY", obuff, "ABUY", + NOTHING, buy_env, NA_INTER_SEE); + return; + } + } + } + } + } while (!from && ((vendor = Next(vendor)) != NOTHING)); + + if (price >= 0) { + if (!from) { + notify(player, T("I can't find that item with that price here.")); + } else { + notify_format(player, T("%s isn't selling that item for that price"), + Name(vendor)); + } + } else if (affordable) { + if (!from) { + notify(player, T("I can't find that item here.")); + } else { + notify_format(player, T("%s isn't selling that item."), Name(vendor)); + } + } else { + notify(player, T("You can't afford that.")); } } *** 1_7_7.1196/src/player.c Thu, 27 May 2004 14:05:53 -0500 dunemush (pennmush/b/47_player.c 1.15.1.1.1.1.1.4.1.6.1.1.1.14 660) --- 1_7_7.1227(w)/src/player.c Tue, 02 Nov 2004 11:00:10 -0600 dunemush (pennmush/b/47_player.c 1.15.1.1.1.1.1.4.1.6.1.1.1.15 660) *************** *** 87,96 **** if (strcmp(crypt(password, "XX"), saved) != 0) /* Nope */ #endif /* HAS_CRYPT */ ! /* crypt() didn't work. Try plaintext, being sure to not allow unencrypted entry of encrypted password */ if ((strcmp(saved, password) != 0) ! && ((strlen(password) < 4) || (password[0] != 'X') ! || (password[1] != 'X'))) { /* Nothing worked. You lose. */ free(saved); return 0; --- 87,97 ---- if (strcmp(crypt(password, "XX"), saved) != 0) /* Nope */ #endif /* HAS_CRYPT */ ! /* crypt() didn't work. Try plaintext, being sure to not ! * allow unencrypted entry of encrypted password */ if ((strcmp(saved, password) != 0) ! || (strlen(password) < 4) ! || ((password[0] == 'X') && (password[1] == 'X'))) { /* Nothing worked. You lose. */ free(saved); return 0; *** 1_7_7.1196/src/parse.c Wed, 25 Aug 2004 20:44:00 -0500 dunemush (pennmush/b/48_parse.c 1.23.1.10.1.2.1.1.1.1.1.2.1.2.1.40 660) --- 1_7_7.1227(w)/src/parse.c Tue, 02 Nov 2004 11:00:10 -0600 dunemush (pennmush/b/48_parse.c 1.23.1.10.1.2.1.1.1.1.1.2.1.2.1.41 660) *************** *** 125,130 **** --- 125,141 ---- return num; } + /** Version of parse_dbref() that doesn't do GoodObject checks */ + dbref + qparse_dbref(const char *s) + { + + if (!s || (*s != NUMBER_TOKEN) || !*(s + 1)) + return NOTHING; + return parse_integer(s + 1); + } + + /** Given a string, parse out an object id or dbref. * \param str string to parse. * \return dbref of object referenced by string, or NOTHING if not a valid *** 1_7_7.1196/src/malias.c Wed, 30 Jun 2004 21:22:16 -0500 dunemush (pennmush/c/3_malias.c 1.36.1.14 660) --- 1_7_7.1227(w)/src/malias.c Tue, 02 Nov 2004 11:00:10 -0600 dunemush (pennmush/c/3_malias.c 1.36.1.15 660) *************** *** 60,65 **** --- 60,66 ---- #include "flags.h" #include "pueblo.h" #include "log.h" + #include "dbio.h" #include "confmagic.h" *** 1_7_7.1196/src/look.c Thu, 19 Aug 2004 14:20:53 -0500 dunemush (pennmush/c/4_look.c 1.21.1.2.1.9.1.1.1.1.1.41 660) --- 1_7_7.1227(w)/src/look.c Tue, 02 Nov 2004 11:00:10 -0600 dunemush (pennmush/c/4_look.c 1.21.1.2.1.9.1.1.1.1.1.45 660) *************** *** 804,818 **** if (ok) { char tbuf1[BUFFER_LEN]; strcpy(tbuf1, object_header(player, Zone(thing))); ! if (Moneybags(player)) ! notify_format(player, ! T("Owner: %s Zone: %s %s: Unlimited"), ! object_header(player, Owner(thing)), tbuf1, MONIES); ! else ! notify_format(player, ! T("Owner: %s Zone: %s %s: %d"), ! object_header(player, Owner(thing)), ! tbuf1, MONIES, Pennies(thing)); notify_format(player, T("Parent: %s"), parent_chain(player, thing)); { struct lock_list *ll; --- 804,813 ---- if (ok) { char tbuf1[BUFFER_LEN]; strcpy(tbuf1, object_header(player, Zone(thing))); ! notify_format(player, ! T("Owner: %s Zone: %s %s: %d"), ! object_header(player, Owner(thing)), ! tbuf1, MONIES, Pennies(thing)); notify_format(player, T("Parent: %s"), parent_chain(player, thing)); { struct lock_list *ll; *************** *** 826,832 **** notify(player, channel_description(thing)); ! notify_format(player, T("Warnings checked: %s"), unparse_warnings(thing)); notify_format(player, T("Created: %s"), show_time(CreTime(thing), 0)); if (!IsPlayer(thing)) --- 821,828 ---- notify(player, channel_description(thing)); ! notify_format(player, T("Warnings checked: %s"), ! unparse_warnings(Warnings(thing))); notify_format(player, T("Created: %s"), show_time(CreTime(thing), 0)); if (!IsPlayer(thing)) *************** *** 952,963 **** void do_score(dbref player) { ! if (Moneybags(player)) notify_format(player, T("You have unlimited %s."), MONIES); ! else notify_format(player, T("You have %d %s."), Pennies(player), Pennies(player) == 1 ? MONEY : MONIES); } /** The inventory command. --- 948,962 ---- void do_score(dbref player) { ! if (NoPay(player)) notify_format(player, T("You have unlimited %s."), MONIES); ! else { notify_format(player, T("You have %d %s."), Pennies(player), Pennies(player) == 1 ? MONEY : MONIES); + if (Moneybags(player)) + notify(player, T("You may give unlimited ducats.")); + } } /** The inventory command. *** 1_7_7.1196/src/game.c Thu, 15 Jul 2004 14:37:11 -0500 dunemush (pennmush/c/10_game.c 1.50.1.8.1.1.1.1.2.1.1.1.2.1.1.4.1.1.1.1.1.1.1.1.1.1.2.1.1.2.1.1.1.1.1.1.1.2.1.1.1.2.1.1.1.1.1.1.1.1.1.5.1.3.1.2.1.2.1.1.1.1.1.1.1.1.1.12.1.3.1.7.1.2.2.1.1.32 660) --- 1_7_7.1227(w)/src/game.c Tue, 02 Nov 2004 11:00:10 -0600 dunemush (pennmush/c/10_game.c 1.50.1.8.1.1.1.1.2.1.1.1.2.1.1.4.1.1.1.1.1.1.1.1.1.1.2.1.1.2.1.1.1.1.1.1.1.2.1.1.1.2.1.1.1.1.1.1.1.1.1.5.1.3.1.2.1.2.1.1.1.1.1.1.1.1.1.12.1.3.1.7.1.2.2.1.1.32.1.1 660) *************** *** 38,44 **** #ifdef I_UNISTD #include #endif - #include #include #include "conf.h" --- 38,43 ---- *************** *** 67,72 **** --- 66,72 ---- #include "flags.h" #include "function.h" #include "help.h" + #include "dbio.h" #ifdef hpux #include *************** *** 776,781 **** --- 776,782 ---- #endif } + extern int dbline; /** Read the game databases. * This function reads in the object, mail, and chat databases. *************** *** 822,925 **** ungetc(c, f); ! /* ok, read it in */ ! do_rawlog(LT_ERR, "ANALYZING: %s", infile); ! if (init_compress(f) < 0) { ! do_rawlog(LT_ERR, "ERROR LOADING"); ! return -1; ! } ! do_rawlog(LT_ERR, "ANALYZING: %s (done)", infile); ! ! /* everything ok */ ! db_close(f); ! ! f = db_open(infile); ! if (!f) ! return -1; ! ! /* ok, read it in */ ! do_rawlog(LT_ERR, "LOADING: %s", infile); ! if (db_read(f) < 0) { ! do_rawlog(LT_ERR, "ERROR LOADING"); ! return -1; ! } ! do_rawlog(LT_ERR, "LOADING: %s (done)", infile); ! ! /* If there's stuff at the end of the db, we may have a panic ! * format db, with everything shoved together. In that case, ! * don't close the file ! */ ! panicdb = ((globals.indb_flags & DBF_PANIC) && !feof(f)); ! /* everything ok */ ! if (!panicdb) db_close(f); ! /* complain about bad config options */ ! if (!GoodObject(PLAYER_START) || (!IsRoom(PLAYER_START))) ! do_rawlog(LT_ERR, T("WARNING: Player_start (#%d) is NOT a room."), ! PLAYER_START); ! if (!GoodObject(MASTER_ROOM) || (!IsRoom(MASTER_ROOM))) ! do_rawlog(LT_ERR, T("WARNING: Master room (#%d) is NOT a room."), ! MASTER_ROOM); ! if (!GoodObject(BASE_ROOM) || (!IsRoom(BASE_ROOM))) ! do_rawlog(LT_ERR, T("WARNING: Base room (#%d) is NOT a room."), BASE_ROOM); ! if (!GoodObject(DEFAULT_HOME) || (!IsRoom(DEFAULT_HOME))) ! do_rawlog(LT_ERR, T("WARNING: Default home (#%d) is NOT a room."), ! DEFAULT_HOME); ! if (!GoodObject(GOD) || (!IsPlayer(GOD))) ! do_rawlog(LT_ERR, T("WARNING: God (#%d) is NOT a player."), GOD); ! ! /* read mail database */ ! if (panicdb) { ! do_rawlog(LT_ERR, T("LOADING: Trying to get mail from %s"), infile); ! if (load_mail(f) <= 0) { ! do_rawlog(LT_ERR, T("FAILED: Reverting to normal maildb")); db_close(f); ! panicdb = 0; ! } ! } ! if (!panicdb) { ! f = db_open(mailfile); /* okay, read it in */ if (f == NULL) { mail_init(); } else { do_rawlog(LT_ERR, "LOADING: %s", mailfile); load_mail(f); do_rawlog(LT_ERR, "LOADING: %s (done)", mailfile); db_close(f); } - } ! init_chatdb(); - if (panicdb) { - do_rawlog(LT_ERR, T("LOADING: Trying to get chat from %s"), infile); - if (load_chatdb(f) <= 0) { - do_rawlog(LT_ERR, T("FAILED: Reverting to normal chatdb")); - db_close(f); - panicdb = 0; - } - } - if (!panicdb) { - f = db_open(options.chatdb); if (f) { do_rawlog(LT_ERR, "LOADING: %s", options.chatdb); if (load_chatdb(f)) { do_rawlog(LT_ERR, "LOADING: %s (done)", options.chatdb); - db_close(f); } else { do_rawlog(LT_ERR, "ERROR LOADING %s", options.chatdb); db_close(f); return -1; } } - } - if (panicdb) db_close(f); return 0; } --- 823,930 ---- ungetc(c, f); ! if (setjmp(db_err) == 0) { ! /* ok, read it in */ ! do_rawlog(LT_ERR, "ANALYZING: %s", infile); ! if (init_compress(f) < 0) { ! do_rawlog(LT_ERR, "ERROR LOADING %s", infile); ! return -1; ! } ! do_rawlog(LT_ERR, "ANALYZING: %s (done)", infile); ! /* everything ok */ db_close(f); ! f = db_open(infile); ! if (!f) ! return -1; ! ! /* ok, read it in */ ! do_rawlog(LT_ERR, "LOADING: %s", infile); ! dbline = 0; ! if (db_read(f) < 0) { ! do_rawlog(LT_ERR, "ERROR LOADING %s", infile); ! return -1; ! } ! do_rawlog(LT_ERR, "LOADING: %s (done)", infile); ! ! /* If there's stuff at the end of the db, we may have a panic ! * format db, with everything shoved together. In that case, ! * don't close the file ! */ ! panicdb = ((globals.indb_flags & DBF_PANIC) && !feof(f)); ! ! /* everything ok */ ! if (!panicdb) db_close(f); ! ! /* complain about bad config options */ ! if (!GoodObject(PLAYER_START) || (!IsRoom(PLAYER_START))) ! do_rawlog(LT_ERR, T("WARNING: Player_start (#%d) is NOT a room."), ! PLAYER_START); ! if (!GoodObject(MASTER_ROOM) || (!IsRoom(MASTER_ROOM))) ! do_rawlog(LT_ERR, T("WARNING: Master room (#%d) is NOT a room."), ! MASTER_ROOM); ! if (!GoodObject(BASE_ROOM) || (!IsRoom(BASE_ROOM))) ! do_rawlog(LT_ERR, T("WARNING: Base room (#%d) is NOT a room."), ! BASE_ROOM); ! if (!GoodObject(DEFAULT_HOME) || (!IsRoom(DEFAULT_HOME))) ! do_rawlog(LT_ERR, T("WARNING: Default home (#%d) is NOT a room."), ! DEFAULT_HOME); ! if (!GoodObject(GOD) || (!IsPlayer(GOD))) ! do_rawlog(LT_ERR, T("WARNING: God (#%d) is NOT a player."), GOD); ! ! /* read mail database */ ! if (panicdb) { ! do_rawlog(LT_ERR, T("LOADING: Trying to get mail from %s"), infile); ! if (load_mail(f) <= 0) { ! do_rawlog(LT_ERR, T("FAILED: Reverting to normal maildb")); ! db_close(f); ! panicdb = 0; ! } ! } else ! f = db_open(mailfile); /* okay, read it in */ if (f == NULL) { mail_init(); } else { do_rawlog(LT_ERR, "LOADING: %s", mailfile); + dbline = 0; load_mail(f); do_rawlog(LT_ERR, "LOADING: %s (done)", mailfile); db_close(f); } ! init_chatdb(); ! ! if (panicdb) { ! do_rawlog(LT_ERR, T("LOADING: Trying to get chat from %s"), infile); ! if (load_chatdb(f) <= 0) { ! do_rawlog(LT_ERR, T("FAILED: Reverting to normal chatdb")); ! db_close(f); ! panicdb = 0; ! } ! } else ! f = db_open(options.chatdb); if (f) { do_rawlog(LT_ERR, "LOADING: %s", options.chatdb); + dbline = 0; if (load_chatdb(f)) { do_rawlog(LT_ERR, "LOADING: %s (done)", options.chatdb); } else { do_rawlog(LT_ERR, "ERROR LOADING %s", options.chatdb); db_close(f); return -1; } } db_close(f); + } else { + do_rawlog(LT_ERR, "ERROR READING DATABASE"); + return -1; + } return 0; } *** 1_7_7.1196/src/funstr.c Sun, 08 Aug 2004 16:28:50 -0500 dunemush (pennmush/c/13_funstr.c 1.28.1.1.1.2.1.4.1.6.1.1.1.1.1.2.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.2.1.3.1.5.1.3.1.2.1.1.1.1.1.1.1.1.1.14.1.21 660) --- 1_7_7.1227(w)/src/funstr.c Tue, 02 Nov 2004 11:00:10 -0600 dunemush (pennmush/c/13_funstr.c 1.28.1.1.1.2.1.4.1.6.1.1.1.1.1.2.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.2.1.3.1.5.1.3.1.2.1.1.1.1.1.1.1.1.1.14.1.23 660) *************** *** 1065,1071 **** FUNCTION(fun_secure) { /* this function smashes all occurences of "unsafe" characters in a string. ! * "unsafe" characters are ( ) [ ] { } $ ^ % , ; \ * these characters get replaced by spaces */ unsigned char *p; --- 1065,1071 ---- FUNCTION(fun_secure) { /* this function smashes all occurences of "unsafe" characters in a string. ! * "unsafe" characters are defined by the escaped_chars table. * these characters get replaced by spaces */ unsigned char *p; *************** *** 1862,1868 **** for (len = 0, ptr = ptrs[i], lastspace = NULL; len < cols[i]; ptr++, len++) { if ((!*ptr) || (*ptr == '\n')) break; ! if (isspace(*ptr)) { lastspace = ptr; } } --- 1862,1868 ---- for (len = 0, ptr = ptrs[i], lastspace = NULL; len < cols[i]; ptr++, len++) { if ((!*ptr) || (*ptr == '\n')) break; ! if (isspace((unsigned char) *ptr)) { lastspace = ptr; } } *************** *** 1874,1880 **** } ptrs[i] = ptr; } else if (*ptr == '\n') { ! for (tptr = ptr; *tptr && tptr >= ptrs[i] && isspace(*tptr); tptr--) ; len = (tptr - ptrs[i]) + 1; if (len > 0) { safe_ansi_string2(as[i], ptrs[i] - (as[i]->text), len, segment, &sp); --- 1874,1881 ---- } ptrs[i] = ptr; } else if (*ptr == '\n') { ! for (tptr = ptr; ! *tptr && tptr >= ptrs[i] && isspace((unsigned char) *tptr); tptr--) ; len = (tptr - ptrs[i]) + 1; if (len > 0) { safe_ansi_string2(as[i], ptrs[i] - (as[i]->text), len, segment, &sp); *************** *** 1884,1890 **** } else if (lastspace) { ptr = lastspace; skipspace = 1; ! for (tptr = ptr; *tptr && tptr >= ptrs[i] && isspace(*tptr); tptr--) ; len = (tptr - ptrs[i]) + 1; if (len > 0) { safe_ansi_string2(as[i], ptrs[i] - (as[i]->text), len, segment, &sp); --- 1885,1892 ---- } else if (lastspace) { ptr = lastspace; skipspace = 1; ! for (tptr = ptr; ! *tptr && tptr >= ptrs[i] && isspace((unsigned char) *tptr); tptr--) ; len = (tptr - ptrs[i]) + 1; if (len > 0) { safe_ansi_string2(as[i], ptrs[i] - (as[i]->text), len, segment, &sp); *************** *** 1915,1921 **** if (i < (ncols - 1) && fslen) safe_str(fieldsep, line, &lp); if (skipspace) ! for (; *ptrs[i] && (*ptrs[i] != '\n') && isspace(*ptrs[i]); ptrs[i]++) ; } if (cols_done == ncols) return 0; --- 1917,1925 ---- if (i < (ncols - 1) && fslen) safe_str(fieldsep, line, &lp); if (skipspace) ! for (; ! *ptrs[i] && (*ptrs[i] != '\n') && isspace((unsigned char) *ptrs[i]); ! ptrs[i]++) ; } if (cols_done == ncols) return 0; *************** *** 1950,1956 **** /* Get column widths */ ncols = 0; for (ptr = args[0]; *ptr; ptr++) { ! while (isspace(*ptr)) ptr++; if (*ptr == '>') { calign[ncols] = AL_RIGHT; --- 1954,1960 ---- /* Get column widths */ ncols = 0; for (ptr = args[0]; *ptr; ptr++) { ! while (isspace((unsigned char) *ptr)) ptr++; if (*ptr == '>') { calign[ncols] = AL_RIGHT; *************** *** 1961,1973 **** } else if (*ptr == '<') { calign[ncols] = AL_LEFT; ptr++; ! } else if (isdigit(*ptr)) { calign[ncols] = AL_LEFT; } else { safe_str(T("#-1 INVALID ALIGN STRING"), buff, bp); return; } ! for (i = 0; *ptr && isdigit(*ptr); ptr++) { i *= 10; i += *ptr - '0'; } --- 1965,1977 ---- } else if (*ptr == '<') { calign[ncols] = AL_LEFT; ptr++; ! } else if (isdigit((unsigned char) *ptr)) { calign[ncols] = AL_LEFT; } else { safe_str(T("#-1 INVALID ALIGN STRING"), buff, bp); return; } ! for (i = 0; *ptr && isdigit((unsigned char) *ptr); ptr++) { i *= 10; i += *ptr - '0'; } *** 1_7_7.1196/src/funlist.c Sun, 08 Aug 2004 16:28:50 -0500 dunemush (pennmush/c/16_funlist.c 1.3.1.1.1.5.1.2.1.1.1.1.1.4.1.2.1.2.1.19.1.2.1.1.1.2.1.5.1.1.1.1.1.1.1.1.1.1.2.1.1.3.1.2.1.1.1.1.1.1.1.1.1.1.1.12.1.14.1.7.1.19 660) --- 1_7_7.1227(w)/src/funlist.c Tue, 02 Nov 2004 11:00:10 -0600 dunemush (pennmush/c/16_funlist.c 1.3.1.1.1.5.1.2.1.1.1.1.1.4.1.2.1.2.1.19.1.2.1.1.1.2.1.5.1.1.1.1.1.1.1.1.1.1.2.1.1.3.1.2.1.1.1.1.1.1.1.1.1.1.1.12.1.14.1.7.1.20 660) *************** *** 43,49 **** static void sane_qsort(void **array, int left, int right, comp_func compare); static void do_itemfuns(char *buff, char **bp, char *str, char *num, char *word, char *sep, int flag); - static int qparse_dbref(const char *s); char *iter_rep[MAX_ITERS]; /**< itext values */ int iter_place[MAX_ITERS]; /**< inum numbers */ --- 43,48 ---- *************** *** 994,1008 **** n = parse_integer(result); return n; - } - - static int - qparse_dbref(const char *s) - { - /* Version of parse_dbref() that doesn't do GoodObject checks */ - if (!s || (*s != NUMBER_TOKEN) || !*(s + 1)) - return NOTHING; - return parse_integer(s + 1); } /** A generic comparer routine to compare two values of any sort type. --- 993,998 ---- *** 1_7_7.1196/src/fundb.c Mon, 09 Aug 2004 14:08:00 -0500 dunemush (pennmush/c/17_fundb.c 1.1.1.1.1.1.1.1.1.1.1.1.1.3.1.1.1.1.1.7.1.3.1.3.1.3.1.2.1.2.1.3.2.1.2.1.2.1.1.1.1.4.1.1.1.1.1.1.1.1.1.1.1.3.1.1.2.2.2.1.1.1.1.1.1.42.1.11 660) --- 1_7_7.1227(w)/src/fundb.c Tue, 02 Nov 2004 11:00:10 -0600 dunemush (pennmush/c/17_fundb.c 1.1.1.1.1.1.1.1.1.1.1.1.1.3.1.1.1.1.1.7.1.3.1.3.1.3.1.2.1.2.1.3.2.1.2.1.2.1.1.1.1.4.1.1.1.1.1.1.1.1.1.1.1.3.1.1.2.2.2.1.1.1.1.1.1.42.1.14 660) *************** *** 32,38 **** #endif extern PRIV attr_privs[]; - const char *do_get_attrib(dbref executor, dbref thing, const char *attrib); static lock_type get_locktype(char *str); extern struct db_stat_info *get_stats(dbref owner); static int lattr_helper(dbref player, dbref thing, dbref parent, --- 32,37 ---- *************** *** 1276,1282 **** safe_str("#-1", buff, bp); return; } ! safe_boolean(eval_lock(victim, it, ltype), buff, bp); return; } --- 1275,1284 ---- safe_str("#-1", buff, bp); return; } ! if (Can_Locate(executor, victim)) ! safe_boolean(eval_lock(victim, it, ltype), buff, bp); ! else ! safe_str("#-1", buff, bp); return; } *** 1_7_7.1196/src/function.c Sun, 08 Aug 2004 16:33:55 -0500 dunemush (pennmush/c/18_function.c 1.29.1.14.1.3.1.6.1.1.1.1.1.14.1.2.1.1.1.7.1.22.1.11.1.3.1.24.1.4 660) --- 1_7_7.1227(w)/src/function.c Tue, 02 Nov 2004 11:00:10 -0600 dunemush (pennmush/c/18_function.c 1.29.1.14.1.3.1.6.1.1.1.1.1.14.1.2.1.1.1.7.1.22.1.11.1.3.1.24.1.4.1.1 660) *************** *** 352,358 **** {"LVEXITS", fun_dbwalker, 1, 1, FN_REG}, {"LVPLAYERS", fun_dbwalker, 1, 1, FN_REG}, {"LVTHINGS", fun_dbwalker, 1, 1, FN_REG}, ! {"LWHO", fun_lwho, 0, 0, FN_REG}, {"MAIL", fun_mail, 0, 2, FN_REG}, {"MAILFROM", fun_mailfrom, 1, 2, FN_REG}, {"MAILSEND", fun_mailsend, 2, 2, FN_REG}, --- 352,358 ---- {"LVEXITS", fun_dbwalker, 1, 1, FN_REG}, {"LVPLAYERS", fun_dbwalker, 1, 1, FN_REG}, {"LVTHINGS", fun_dbwalker, 1, 1, FN_REG}, ! {"LWHO", fun_lwho, 0, 1, FN_REG}, {"MAIL", fun_mail, 0, 2, FN_REG}, {"MAILFROM", fun_mailfrom, 1, 2, FN_REG}, {"MAILSEND", fun_mailsend, 2, 2, FN_REG}, *** 1_7_7.1196/src/flags.c Tue, 24 Aug 2004 09:30:54 -0500 dunemush (pennmush/c/20_flags.c 1.1.1.1.1.1.1.1.1.1.1.1.1.6.1.2.1.1.1.1.1.2.2.2.2.1.2.1.1.3.1.2.1.1.1.1.1.1.1.1.1.3.1.9.1.2.2.1.1.2.1.56.1.12.1.1.1.29.1.1 660) --- 1_7_7.1227(w)/src/flags.c Tue, 02 Nov 2004 11:00:10 -0600 dunemush (pennmush/c/20_flags.c 1.1.1.1.1.1.1.1.1.1.1.1.1.6.1.2.1.1.1.1.1.2.2.2.2.1.2.1.1.3.1.2.1.1.1.1.1.1.1.1.1.3.1.9.1.2.2.1.1.2.1.56.1.12.1.1.1.29.1.2 660) *************** *** 43,48 **** --- 43,49 ---- #include "dbdefs.h" #include "lock.h" #include "log.h" + #include "dbio.h" #include "oldflags.h" #include "confmagic.h" *************** *** 53,58 **** --- 54,61 ---- static int has_flag_ns(FLAGSPACE * n, dbref thing, FLAG *f); static FLAG *flag_read(FILE * in); + static FLAG *flag_read_oldstyle(FILE * in); + static void flag_read_all_oldstyle(FILE * in, const char *ns); static void flag_write(FILE * out, FLAG *f, const char *name); static FLAG *flag_hash_lookup(FLAGSPACE * n, const char *name, int type); static FLAG *clone_flag(FLAG *f); *************** *** 480,486 **** /* Read in a flag from a file and return it */ static FLAG * ! flag_read(FILE * in) { FLAG *f; char *c; --- 483,489 ---- /* Read in a flag from a file and return it */ static FLAG * ! flag_read_oldstyle(FILE * in) { FLAG *f; char *c; *************** *** 501,507 **** } static FLAG * ! flag_alias_read(FILE * in, char *alias, FLAGSPACE * n) { FLAG *f; char *c; --- 504,510 ---- } static FLAG * ! flag_alias_read_oldstyle(FILE * in, char *alias, FLAGSPACE * n) { FLAG *f; char *c; *************** *** 539,546 **** * \param in file pointer to read from. * \param ns name of namespace to search. */ ! void ! flag_read_all(FILE * in, const char *ns) { FLAG *f; FLAGSPACE *n; --- 542,549 ---- * \param in file pointer to read from. * \param ns name of namespace to search. */ ! static void ! flag_read_all_oldstyle(FILE * in, const char *ns) { FLAG *f; FLAGSPACE *n; *************** *** 552,586 **** } /* If we are reading flags from the db, they are definitive. */ clear_all_flags(n); ! while ((f = flag_read(in))) { flag_add(n, f->name, f); } /* Assumes we'll always have at least one alias */ ! while ((f = flag_alias_read(in, alias, n))) { flag_add(n, alias, f); } flag_add_additional(n); } /* Write a flag out to a file */ static void flag_write(FILE * out, FLAG *f, const char *name) { ! putstring(out, name); ! putstring(out, tprintf("%c", f->letter)); ! putref(out, f->type); ! putref(out, f->perms); ! putref(out, f->negate_perms); } /* Write a flag alias out to a file */ static void flag_alias_write(FILE * out, FLAG *f, const char *name) { ! /* Real name */ ! putstring(out, f->name); ! /* Alias */ ! putstring(out, name); } /** Write flags and aliases to the database. This function expects --- 555,684 ---- } /* If we are reading flags from the db, they are definitive. */ clear_all_flags(n); ! while ((f = flag_read_oldstyle(in))) { flag_add(n, f->name, f); } /* Assumes we'll always have at least one alias */ ! while ((f = flag_alias_read_oldstyle(in, alias, n))) { flag_add(n, alias, f); } flag_add_additional(n); } + /* Read in a flag from a file and return it */ + static FLAG * + flag_read(FILE * in) + { + FLAG *f; + char *c; + char *tmp; + + db_read_this_labeled_string(in, "name", &tmp); + c = mush_strdup(tmp, "flag name"); + f = new_flag(); + f->name = c; + db_read_this_labeled_string(in, "letter", &tmp); + f->letter = *tmp; + f->bitpos = -1; + db_read_this_labeled_string(in, "type", &tmp); + f->type = string_to_privs(type_privs, tmp, 0); + db_read_this_labeled_string(in, "perms", &tmp); + f->perms = string_to_privs(flag_privs, tmp, 0); + db_read_this_labeled_string(in, "negate_perms", &tmp); + f->negate_perms = string_to_privs(flag_privs, tmp, 0); + return f; + } + + static FLAG * + flag_alias_read(FILE * in, char *alias, FLAGSPACE * n) + { + FLAG *f; + char *c; + char *tmp; + /* Real name first */ + db_read_this_labeled_string(in, "name", &tmp); + c = mush_strdup(tmp, "flag alias"); + f = match_flag_ns(n, c); + if (!f) { + /* Corrupt db. Recover as well as we can. */ + do_rawlog(LT_ERR, + T + ("FLAG READ: flag alias %s matches no known flag. Skipping this alias."), + c); + mush_free(c, "flag alias"); + (void) getstring_noalloc(in); + return NULL; + } else + mush_free(c, "flag alias"); + + /* Get the alias name */ + db_read_this_labeled_string(in, "alias", &tmp); + strcpy(alias, tmp); + return f; + } + + /** Read flags and aliases from the database. This function expects + * to receive file pointer that's already reading in a database file + * and pointing at the start of the flag table. It reads the flags, + * reads the aliases, and then does any additional flag adding that + * needs to happen. + * \param in file pointer to read from. + * \param ns name of namespace to search. + */ + void + flag_read_all(FILE * in, const char *ns) + { + FLAG *f; + FLAGSPACE *n; + char alias[BUFFER_LEN]; + int count; + + if (!(globals.indb_flags & DBF_LABELS)) { + flag_read_all_oldstyle(in, ns); + return; + } + + if (!(n = (FLAGSPACE *) hashfind(ns, &htab_flagspaces))) { + do_rawlog(LT_ERR, T("FLAG READ: Unable to locate flagspace %s."), ns); + return; + } + /* If we are reading flags from the db, they are definitive. */ + clear_all_flags(n); + db_read_this_labeled_number(in, "flagcount", &count); + for (; count > 0; count--) { + if ((f = flag_read(in))) + flag_add(n, f->name, f); + } + /* Assumes we'll always have at least one alias */ + db_read_this_labeled_number(in, "flagaliascount", &count); + for (; count > 0; count--) { + if ((f = flag_alias_read(in, alias, n))) + flag_add(n, alias, f); + } + flag_add_additional(n); + } + + /* Write a flag out to a file */ static void flag_write(FILE * out, FLAG *f, const char *name) { ! db_write_labeled_string(out, " name", name); ! db_write_labeled_string(out, " letter", tprintf("%c", f->letter)); ! db_write_labeled_string(out, " type", privs_to_string(type_privs, f->type)); ! db_write_labeled_string(out, " perms", ! privs_to_string(flag_privs, f->perms)); ! db_write_labeled_string(out, " negate_perms", ! privs_to_string(flag_privs, f->negate_perms)); } + /* Write a flag alias out to a file */ static void flag_alias_write(FILE * out, FLAG *f, const char *name) { ! db_write_labeled_string(out, " name", f->name); ! db_write_labeled_string(out, " alias", name); } /** Write flags and aliases to the database. This function expects *************** *** 591,597 **** void flag_write_all(FILE * out, const char *ns) { ! int i; FLAG *f; FLAGSPACE *n; char flagname[BUFFER_LEN]; --- 689,695 ---- void flag_write_all(FILE * out, const char *ns) { ! int i, count; FLAG *f; FLAGSPACE *n; char flagname[BUFFER_LEN]; *************** *** 601,615 **** return; } /* Write out canonical flags first */ for (i = 0; i < n->flagbits; i++) { if (n->flags[i]) flag_write(out, n->flags[i], n->flags[i]->name); } - putstring(out, "FLAG ALIASES"); /* Now write out aliases. An alias is a flag in the ptab whose * name isn't the same as the name of the canonical flag in its * bit position */ f = ptab_firstentry_new(n->tab, flagname); while (f) { if (strcmp(n->flags[f->bitpos]->name, flagname)) { --- 699,726 ---- return; } /* Write out canonical flags first */ + count = 0; + for (i = 0; i < n->flagbits; i++) { + if (n->flags[i]) + count++; + } + db_write_labeled_number(out, "flagcount", count); for (i = 0; i < n->flagbits; i++) { if (n->flags[i]) flag_write(out, n->flags[i], n->flags[i]->name); } /* Now write out aliases. An alias is a flag in the ptab whose * name isn't the same as the name of the canonical flag in its * bit position */ + count = 0; + f = ptab_firstentry_new(n->tab, flagname); + while (f) { + if (strcmp(n->flags[f->bitpos]->name, flagname)) + count++; + f = ptab_nextentry_new(n->tab, flagname); + } + db_write_labeled_number(out, "flagaliascount", count); f = ptab_firstentry_new(n->tab, flagname); while (f) { if (strcmp(n->flags[f->bitpos]->name, flagname)) { *************** *** 618,624 **** } f = ptab_nextentry_new(n->tab, flagname); } - putstring(out, "END OF FLAGS"); } /** Initialize the flagspaces. --- 729,734 ---- *** 1_7_7.1196/src/extmail.c Fri, 20 Aug 2004 12:07:46 -0500 dunemush (pennmush/c/22_extmail.c 1.44.1.7.1.5.1.9.1.1.1.1.1.27 660) --- 1_7_7.1227(w)/src/extmail.c Tue, 02 Nov 2004 11:00:10 -0600 dunemush (pennmush/c/22_extmail.c 1.44.1.7.1.5.1.9.1.1.1.1.1.28 660) *************** *** 70,76 **** #include #endif #include - #include #include "conf.h" #include "externs.h" --- 70,75 ---- *************** *** 88,100 **** #include "log.h" #include "lock.h" #include "command.h" #include "confmagic.h" - - extern jmp_buf db_err; - - /** Evaluate a function, and jump on error */ - #define OUTPUT(fun) do { if ((fun) < 0) longjmp(db_err, 1); } while (0) extern int do_convtime(const char *str, struct tm *ttm); /* funtime.c */ --- 87,95 ---- #include "log.h" #include "lock.h" #include "command.h" + #include "dbio.h" #include "confmagic.h" extern int do_convtime(const char *str, struct tm *ttm); /* funtime.c */ *** 1_7_7.1196/src/extchat.c Sun, 11 Jul 2004 11:36:53 -0500 dunemush (pennmush/c/23_extchat.c 1.1.1.1.1.1.1.1.1.2.1.1.1.3.1.1.1.5.1.1.1.1.1.5.1.2.1.3.1.3.1.1.1.4.1.2.1.6.1.2.1.1.2.4.2.9.1.2.1.2.1.3.1.2.1.2.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.3.1.2.1.1.2.1.1.2.1.1.1.1.1.1.1.1.1.16.1.27 660) --- 1_7_7.1227(w)/src/extchat.c Tue, 02 Nov 2004 11:00:10 -0600 dunemush (pennmush/c/23_extchat.c 1.1.1.1.1.1.1.1.1.2.1.1.1.3.1.1.1.5.1.1.1.1.1.5.1.2.1.3.1.3.1.1.1.4.1.2.1.6.1.2.1.1.2.4.2.9.1.2.1.2.1.3.1.2.1.2.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.3.1.2.1.1.2.1.1.2.1.1.1.1.1.1.1.1.1.16.1.27.1.4 660) *************** *** 14,20 **** #ifdef I_SYS_TYPES #include #endif - #include #include #include "conf.h" #include "externs.h" --- 14,19 ---- *************** *** 34,55 **** #include "dbdefs.h" #include "function.h" #include "command.h" #include "confmagic.h" - extern jmp_buf db_err; - - /** Evaluate a function and jump on error. */ - #define OUTPUT(fun) do { if ((fun) < 0) longjmp(db_err, 1); } while (0) - static CHAN *new_channel(void); static CHANLIST *new_chanlist(void); static CHANUSER *new_user(dbref who); static void free_channel(CHAN *c); static void free_chanlist(CHANLIST *cl); static void free_user(CHANUSER *u); static int load_channel(FILE * fp, CHAN *ch); static int load_chanusers(FILE * fp, CHAN *ch); static void insert_channel(CHAN **ch); static void remove_channel(CHAN *ch); static void insert_obj_chan(dbref who, CHAN **ch); --- 33,53 ---- #include "dbdefs.h" #include "function.h" #include "command.h" + #include "dbio.h" #include "confmagic.h" static CHAN *new_channel(void); static CHANLIST *new_chanlist(void); static CHANUSER *new_user(dbref who); static void free_channel(CHAN *c); static void free_chanlist(CHANLIST *cl); static void free_user(CHANUSER *u); + static int load_chatdb_oldstyle(FILE * fp); static int load_channel(FILE * fp, CHAN *ch); static int load_chanusers(FILE * fp, CHAN *ch); + static int load_labeled_channel(FILE * fp, CHAN *ch); + static int load_labeled_chanusers(FILE * fp, CHAN *ch); static void insert_channel(CHAN **ch); static void remove_channel(CHAN *ch); static void insert_obj_chan(dbref who, CHAN **ch); *************** *** 174,181 **** * \retval 1 success * \retval 0 failure */ ! int ! load_chatdb(FILE * fp) { int i; CHAN *ch; --- 172,179 ---- * \retval 1 success * \retval 0 failure */ ! static int ! load_chatdb_oldstyle(FILE * fp) { int i; CHAN *ch; *************** *** 212,217 **** --- 210,285 ---- return 1; } + extern char db_timestamp[]; + + /** Load the chat database from a file. + * \param fp pointer to file to read from. + * \retval 1 success + * \retval 0 failure + */ + int + load_chatdb(FILE * fp) + { + int i, flags; + CHAN *ch; + char buff[20]; + char *chat_timestamp; + + i = fgetc(fp); + if (i == EOF) { + do_rawlog(LT_ERR, T("CHAT: Invalid database format!")); + longjmp(db_err, 1); + } else if (i != '+') { + ungetc(i, fp); + return load_chatdb_oldstyle(fp); + } + + i = fgetc(fp); + + if (i != 'V') { + do_rawlog(LT_ERR, T("CHAT: Invalid database format!")); + longjmp(db_err, 1); + } + + flags = getref(fp); + + db_read_this_labeled_string(fp, "savedtime", &chat_timestamp); + + if (strcmp(chat_timestamp, db_timestamp)) + do_rawlog(LT_ERR, + T + ("CHAT: warning: chatdb and game db were saved at different times!")); + + /* How many channels? */ + db_read_this_labeled_number(fp, "channels", &num_channels); + if (num_channels > MAX_CHANNELS) + return 0; + + /* Load all channels */ + for (i = 0; i < num_channels; i++) { + ch = new_channel(); + if (!ch) + return 0; + if (!load_labeled_channel(fp, ch)) { + do_rawlog(LT_ERR, T("Unable to load channel %d."), i); + free_channel(ch); + return 0; + } + insert_channel(&ch); + } + num_channels = i; + + /* Check for **END OF DUMP*** */ + fgets(buff, sizeof buff, fp); + if (!buff) + do_rawlog(LT_ERR, T("CHAT: No end-of-dump marker in the chat database.")); + else if (strcmp(buff, EOD) != 0) + do_rawlog(LT_ERR, T("CHAT: Trailing garbage in the chat database.")); + + return 1; + } + + /* Malloc memory for a new channel, and initialize it */ static CHAN * new_channel(void) *************** *** 242,247 **** --- 310,316 ---- } + /* Malloc memory for a new user, and initialize it */ static CHANUSER * new_user(dbref who) *************** *** 313,318 **** --- 382,433 ---- return 1; } + /* Load in a single channel into position i. Return 1 if + * successful, 0 otherwise. + */ + static int + load_labeled_channel(FILE * fp, CHAN *ch) + { + char *tmp; + int i; + dbref d; + char *label, *value; + + db_read_this_labeled_string(fp, "name", &tmp); + strcpy(ChanName(ch), tmp); + db_read_this_labeled_string(fp, "description", &tmp); + strcpy(ChanTitle(ch), tmp); + db_read_this_labeled_number(fp, "flags", &i); + ChanType(ch) = i; + db_read_this_labeled_dbref(fp, "creator", &d); + ChanCreator(ch) = d; + db_read_this_labeled_number(fp, "cost", &i); + ChanCost(ch) = i; + ChanNumMsgs(ch) = 0; + while (1) { + db_read_labeled_string(fp, &label, &value); + if (strcmp(label, "lock")) + break; + else if (strcmp(value, "join") == 0) + ChanJoinLock(ch) = getboolexp(fp, chan_join_lock); + else if (strcmp(value, "speak") == 0) + ChanSpeakLock(ch) = getboolexp(fp, chan_speak_lock); + else if (strcmp(value, "modify") == 0) + ChanModLock(ch) = getboolexp(fp, chan_mod_lock); + else if (strcmp(value, "see") == 0) + ChanSeeLock(ch) = getboolexp(fp, chan_see_lock); + else if (strcmp(value, "hide") == 0) + ChanHideLock(ch) = getboolexp(fp, chan_hide_lock); + } + ChanNumUsers(ch) = parse_integer(value); + ChanMaxUsers(ch) = ChanNumUsers(ch); + ChanUsers(ch) = NULL; + if (ChanNumUsers(ch) > 0) + ChanNumUsers(ch) = load_labeled_chanusers(fp, ch); + return 1; + } + + /* Load the *channel's user list. Return number of users on success, or 0 */ static int load_chanusers(FILE * fp, CHAN *ch) *************** *** 341,346 **** --- 456,492 ---- return num; } + /* Load the *channel's user list. Return number of users on success, or 0 */ + static int + load_labeled_chanusers(FILE * fp, CHAN *ch) + { + int i, num = 0, n; + char *tmp; + CHANUSER *user; + dbref player; + for (i = 0; i < ChanNumUsers(ch); i++) { + db_read_this_labeled_dbref(fp, "dbref", &player); + /* Don't bother if the player isn't a valid dbref or the wrong type */ + if (GoodObject(player) && Chan_Ok_Type(ch, player)) { + user = new_user(player); + db_read_this_labeled_number(fp, "flags", &n); + CUtype(user) = n; + db_read_this_labeled_string(fp, "title", &tmp); + strcpy(CUtitle(user), tmp); + CUnext(user) = NULL; + if (insert_user(user, ch)) + num++; + } else { + /* But be sure to read (and discard) the player's info */ + do_log(LT_ERR, 0, 0, T("Bad object #%d removed from channel %s"), + player, ChanName(ch)); + db_read_this_labeled_number(fp, "type", &n); + db_read_this_labeled_string(fp, "title", &tmp); + } + } + return num; + } + /* Insert the channel onto the list of channels, sorted by name */ static void *************** *** 596,605 **** save_chatdb(FILE * fp) { CHAN *ch; /* How many channels? */ ! putref(fp, num_channels); ! for (ch = channels; ch; ch = ch->next) { save_channel(fp, ch); } --- 742,753 ---- save_chatdb(FILE * fp) { CHAN *ch; + int default_flags = 0; /* How many channels? */ ! OUTPUT(fprintf(fp, "+V%d\n", default_flags)); ! db_write_labeled_string(fp, "savedtime", show_time(mudtime, 1)); ! db_write_labeled_number(fp, "channels", num_channels); for (ch = channels; ch; ch = ch->next) { save_channel(fp, ch); } *************** *** 613,629 **** save_channel(FILE * fp, CHAN *ch) { CHANUSER *cu; ! putstring(fp, ChanName(ch)); ! putstring(fp, ChanTitle(ch)); ! putref(fp, ChanType(ch)); ! putref(fp, ChanCreator(ch)); ! putref(fp, ChanCost(ch)); putboolexp(fp, ChanJoinLock(ch)); putboolexp(fp, ChanSpeakLock(ch)); putboolexp(fp, ChanModLock(ch)); putboolexp(fp, ChanSeeLock(ch)); putboolexp(fp, ChanHideLock(ch)); ! putref(fp, ChanNumUsers(ch)); for (cu = ChanUsers(ch); cu; cu = cu->next) save_chanuser(fp, cu); return 1; --- 761,783 ---- save_channel(FILE * fp, CHAN *ch) { CHANUSER *cu; ! ! db_write_labeled_string(fp, " name", ChanName(ch)); ! db_write_labeled_string(fp, " description", ChanTitle(ch)); ! db_write_labeled_number(fp, " flags", ChanType(ch)); ! db_write_labeled_dbref(fp, " creator", ChanCreator(ch)); ! db_write_labeled_number(fp, " cost", ChanCost(ch)); ! db_write_labeled_string(fp, " lock", "join"); putboolexp(fp, ChanJoinLock(ch)); + db_write_labeled_string(fp, " lock", "speak"); putboolexp(fp, ChanSpeakLock(ch)); + db_write_labeled_string(fp, " lock", "modify"); putboolexp(fp, ChanModLock(ch)); + db_write_labeled_string(fp, " lock", "see"); putboolexp(fp, ChanSeeLock(ch)); + db_write_labeled_string(fp, " lock", "hide"); putboolexp(fp, ChanHideLock(ch)); ! db_write_labeled_number(fp, " users", ChanNumUsers(ch)); for (cu = ChanUsers(ch); cu; cu = cu->next) save_chanuser(fp, cu); return 1; *************** *** 633,641 **** static int save_chanuser(FILE * fp, CHANUSER *user) { ! putref(fp, CUdbref(user)); ! putref(fp, CUtype(user)); ! putstring(fp, CUtitle(user)); return 1; } --- 787,795 ---- static int save_chanuser(FILE * fp, CHANUSER *user) { ! db_write_labeled_dbref(fp, " dbref", CUdbref(user)); ! db_write_labeled_number(fp, " flags", CUtype(user)); ! db_write_labeled_string(fp, " title", CUtitle(user)); return 1; } *************** *** 1193,1206 **** } } ! /** Parse a chat token command. * \verbatim * This function hacks up something of the form "+ ", ! * finding the two args, and passes it to do_chat * \endverbatim * \param player the enactor. * \param command the command to parse. ! * \retval 1 chat was successful. * \retval 0 chat failed (no such channel, etc.) */ int --- 1347,1361 ---- } } ! /** Parse a chat token command, but don't chat with it. * \verbatim * This function hacks up something of the form "+ ", ! * finding the two args, and returns 1 if the channel exists, ! * otherwise 0. * \endverbatim * \param player the enactor. * \param command the command to parse. ! * \retval 1 channel exists * \retval 0 chat failed (no such channel, etc.) */ int *************** *** 1208,1232 **** { char *arg1; char *arg2; - char tbuf1[MAX_COMMAND_LEN]; char *s; ! strncpy(tbuf1, command, MAX_COMMAND_LEN - 1); /* don't hack it up */ ! tbuf1[MAX_COMMAND_LEN - 1] = '\0'; ! s = tbuf1; ! arg1 = s; while (*s && !isspace((unsigned char) *s)) s++; ! if (*s) { ! *s++ = '\0'; ! while (*s && isspace((unsigned char) *s)) ! s++; ! } arg2 = s; ! return do_chat_by_name(player, arg1, arg2, 0); } --- 1363,1397 ---- { char *arg1; char *arg2; char *s; + char ch; + CHAN *c; ! s = command; arg1 = s; while (*s && !isspace((unsigned char) *s)) s++; ! if (!*s) ! return 0; ! ! ch = *s; arg2 = s; + *arg2++ = '\0'; + while (*arg2 && isspace((unsigned char) *arg2)) + arg2++; ! /* arg1 is channel name, arg2 is text. */ ! switch (find_channel_partial_on(arg1, &c, player)) { ! case CMATCH_AMBIG: ! case CMATCH_EXACT: ! case CMATCH_PARTIAL: ! *s = '='; ! return 1; ! default: ! *s = ch; ! return 0; ! } } *************** *** 2757,2763 **** int ns = string_prefix(called_as, "NS"); int flags = PEMIT_SILENT; flags |= (ns ? PEMIT_SPOOF : 0); ! if (!command_check_byname(executor, ns ? "@nsemit" : "@emit") || fun->flags & FN_NOSIDEFX) { safe_str(T(e_perm), buff, bp); return; --- 2922,2928 ---- int ns = string_prefix(called_as, "NS"); int flags = PEMIT_SILENT; flags |= (ns ? PEMIT_SPOOF : 0); ! if (!command_check_byname(executor, ns ? "@nscemit" : "@cemit") || fun->flags & FN_NOSIDEFX) { safe_str(T(e_perm), buff, bp); return; *** 1_7_7.1196/src/db.c Wed, 30 Jun 2004 15:00:16 -0500 dunemush (pennmush/c/25_db.c 1.26.1.1.1.1.1.6.1.1.1.24 660) --- 1_7_7.1227(w)/src/db.c Tue, 02 Nov 2004 11:00:10 -0600 dunemush (pennmush/c/25_db.c 1.26.1.1.1.1.1.6.1.1.1.28 660) *************** *** 18,25 **** #include #endif #include - #include #include "conf.h" #include "externs.h" #include "mushdb.h" #include "attrib.h" --- 18,25 ---- #include #endif #include #include "conf.h" + #include "dbio.h" #include "externs.h" #include "mushdb.h" #include "attrib.h" *************** *** 31,50 **** #include "log.h" #include "strtree.h" #include "parse.h" #include "htab.h" #include "extmail.h" #include "confmagic.h" ! #ifdef WIN32 ! #ifndef __MINGW32__ void shutdown_checkpoint(void); #endif - #endif - - extern jmp_buf db_err; - - /** Run a function, and jump if error */ - #define OUTPUT(fun) do { if ((fun) < 0) longjmp(db_err, 1); } while (0) /** Get a ref out of the database if a given db flag is set */ #define MAYBE_GET(f,x) \ --- 31,44 ---- #include "log.h" #include "strtree.h" #include "parse.h" + #include "privtab.h" #include "htab.h" #include "extmail.h" #include "confmagic.h" ! #ifdef WIN32SERVICES void shutdown_checkpoint(void); #endif /** Get a ref out of the database if a given db flag is set */ #define MAYBE_GET(f,x) \ *************** *** 53,63 **** --- 47,61 ---- int loading_db = 0; /**< Are we loading the database? */ + char db_timestamp[100]; /**< Time the read database was saved. */ + struct object *db = NULL; /**< The object db array */ dbref db_top = 0; /**< The number of objects in the db array */ dbref errobj; /**< Dbref of object on which an error has occurred */ + int dbline = 0; /**< Line of the database file being read */ + /** String that markes the end of dumps */ const char *EOD = "***END OF DUMP***\n"; *************** *** 74,86 **** static void db_write_obj_basic(FILE * f, dbref i, struct object *o); int db_paranoid_write_object(FILE * f, dbref i, int flag); void putlocks(FILE * f, lock_list *l); void getlocks(dbref i, FILE * f); ! void get_new_locks(dbref i, FILE * f); int get_list(FILE * f, dbref i); void db_free(void); static void init_objdata_htab(int size); static void db_write_flags(FILE * f); StrTree object_names; /**< String tree of object names */ extern StrTree atr_names; --- 72,87 ---- static void db_write_obj_basic(FILE * f, dbref i, struct object *o); int db_paranoid_write_object(FILE * f, dbref i, int flag); + int db_write_object(FILE * f, dbref i); void putlocks(FILE * f, lock_list *l); void getlocks(dbref i, FILE * f); ! void get_new_locks(dbref i, FILE * f, int c); ! void db_read_attrs(FILE * f, dbref i, int c); int get_list(FILE * f, dbref i); void db_free(void); static void init_objdata_htab(int size); static void db_write_flags(FILE * f); + static dbref db_read_oldstyle(FILE * f); StrTree object_names; /**< String tree of object names */ extern StrTree atr_names; *************** *** 258,269 **** OUTPUT(putc('\n', f)); } ! ! static void ! get_logical_line(FILE * f, char **label, char **value) { static char lbuf[BUFFER_LEN], vbuf[BUFFER_LEN]; - static int line; int c; char *p; --- 259,278 ---- OUTPUT(putc('\n', f)); } ! /** Read a labeled entry from a database. ! * Labeled entries look like 'label entry', and are used ! * extensively in the current database format, and to a lesser ! * extent in older versions. ! * \param f the file to read from ! * \param label pointer to update to the address of a static ! * buffer containing the label that was read. ! * \param value pointer to update to the address of a static ! * buffer containing the value that was read. ! */ ! void ! db_read_labeled_string(FILE * f, char **label, char **value) { static char lbuf[BUFFER_LEN], vbuf[BUFFER_LEN]; int c; char *p; *************** *** 272,284 **** /* invariant: we start at the beginning of a line. */ ! line++; do { c = getc(f); while (isspace(c)) { if (c == '\n') ! line++; c = getc(f); } if (c == '#') { --- 281,293 ---- /* invariant: we start at the beginning of a line. */ ! dbline++; do { c = getc(f); while (isspace(c)) { if (c == '\n') ! dbline++; c = getc(f); } if (c == '#') { *************** *** 286,329 **** /* nothing */ } if (c == '\n') ! line++; } } while (c != EOF && isspace(c)); - /* return empty strings on end of file */ - if (c == EOF) { ! *lbuf = '\0'; ! *vbuf = '\0'; ! return; } /* invariant: we should have the first character of a label in 'c'. */ p = lbuf; do { ! if (c != '_' && c != '-' && c != '!' && c != '.' && c != '>' && c != '<' && /* these really should only be first time */ !isalnum(c)) { do_rawlog(LT_ERR, "DB: Illegal character '%c'(%d) in label, line %d", ! c, c, line); ! do_rawlog(LT_ERR, "Aborting..."); ! exit(1); } safe_chr(c, lbuf, &p); c = getc(f); } while (c != EOF && !isspace(c)); *p++ = '\0'; if (p >= lbuf + BUFFER_LEN) ! do_rawlog(LT_ERR, "DB: warning: very long label, line %d", line); /* suck up separating whitespace */ while (c != '\n' && c != EOF && isspace(c)) c = getc(f); ! /* check for presence of a value */ if (c == EOF || c == '\n') { ! *vbuf = '\0'; ! return; } /* invariant: we should have the first character of a value in 'c'. */ --- 295,338 ---- /* nothing */ } if (c == '\n') ! dbline++; } } while (c != EOF && isspace(c)); if (c == EOF) { ! do_rawlog(LT_ERR, T("DB: Unexpected EOF at line %d"), dbline); ! longjmp(db_err, 1); } /* invariant: we should have the first character of a label in 'c'. */ p = lbuf; do { ! if (c != '_' && c != '-' && c != '!' && c != '.' && c != '>' && c != '<' && c != '#' && /* these really should only be first time */ !isalnum(c)) { do_rawlog(LT_ERR, "DB: Illegal character '%c'(%d) in label, line %d", ! c, c, dbline); ! longjmp(db_err, 1); } safe_chr(c, lbuf, &p); c = getc(f); } while (c != EOF && !isspace(c)); *p++ = '\0'; if (p >= lbuf + BUFFER_LEN) ! do_rawlog(LT_ERR, "DB: warning: very long label, line %d", dbline); /* suck up separating whitespace */ while (c != '\n' && c != EOF && isspace(c)) c = getc(f); ! /* check for presence of a value, which we must have. */ if (c == EOF || c == '\n') { ! if (c == EOF) ! do_rawlog(LT_ERR, T("DB: Unexpected EOF at line %d"), dbline); ! else ! do_rawlog(LT_ERR, T("DB: Missing value for '%s' at line %d"), lbuf, ! dbline); ! longjmp(db_err, 1); } /* invariant: we should have the first character of a value in 'c'. */ *************** *** 332,338 **** if (c == '"') { /* quoted string */ int sline; ! sline = line; for (;;) { c = getc(f); if (c == '"') --- 341,347 ---- if (c == '"') { /* quoted string */ int sline; ! sline = dbline; for (;;) { c = getc(f); if (c == '"') *************** *** 342,375 **** if (c == EOF) { do_rawlog(LT_ERR, "DB: Unclosed quoted string starting on line %d", sline); ! do_rawlog(LT_ERR, "Aborting..."); ! exit(1); } if (c == '\0') do_rawlog(LT_ERR, "DB: warning: null in quoted string, remainder lost, line %d", ! line); if (c == '\n') ! line++; safe_chr(c, vbuf, &p); } do { c = getc(f); if (c != EOF && !isspace(c)) { ! do_rawlog(LT_ERR, "DB: Garbage after quoted string, line %d", line); ! do_rawlog(LT_ERR, "Aborting..."); ! exit(1); } } while (c != '\n' && c != EOF); } else { /* non-quoted value */ do { if (c != '_' && c != '-' && c != '!' && c != '.' && ! !isalnum(c) && !isspace(c)) { do_rawlog(LT_ERR, "DB: Illegal character '%c'(%d) in value, line %d", ! c, c, line); ! do_rawlog(LT_ERR, "Aborting..."); ! exit(1); } safe_chr(c, vbuf, &p); c = getc(f); --- 351,381 ---- if (c == EOF) { do_rawlog(LT_ERR, "DB: Unclosed quoted string starting on line %d", sline); ! longjmp(db_err, 1); } if (c == '\0') do_rawlog(LT_ERR, "DB: warning: null in quoted string, remainder lost, line %d", ! dbline); if (c == '\n') ! dbline++; safe_chr(c, vbuf, &p); } do { c = getc(f); if (c != EOF && !isspace(c)) { ! do_rawlog(LT_ERR, "DB: Garbage after quoted string, line %d", dbline); ! longjmp(db_err, 1); } } while (c != '\n' && c != EOF); } else { /* non-quoted value */ do { if (c != '_' && c != '-' && c != '!' && c != '.' && ! c != '#' && !isalnum(c) && !isspace(c)) { do_rawlog(LT_ERR, "DB: Illegal character '%c'(%d) in value, line %d", ! c, c, dbline); ! longjmp(db_err, 1); } safe_chr(c, vbuf, &p); c = getc(f); *************** *** 382,412 **** } *p++ = '\0'; if (p >= vbuf + BUFFER_LEN) ! do_rawlog(LT_ERR, "DB: warning: very long value, line %d", line); /* note no line increment for final newline because of initial increment */ } static void db_write_label(FILE * f, char const *l) { ! fputs(l, f); ! putc(' ', f); } ! static void db_write_labeled_string(FILE * f, char const *label, char const *value) { db_write_label(f, label); putstring(f, value); } ! static void db_write_labeled_number(FILE * f, char const *label, int value) { OUTPUT(fprintf(f, "%s %d\n", label, value)); } /** Write a boolexp to a file in unparsed (text) form. * \param f file pointer to write to. * \param b pointer to boolexp to write. --- 388,524 ---- } *p++ = '\0'; if (p >= vbuf + BUFFER_LEN) ! do_rawlog(LT_ERR, "DB: warning: very long value, line %d", dbline); /* note no line increment for final newline because of initial increment */ } + /** Read a string with a given label. + * If the label read is different than the one being checked, the + * database load will abort with an error. + * \param f the file to read from. + * \param label the label that should be read. + * \param value pointer to update to the address of a static + * buffer containing the value that was read. + */ + void + db_read_this_labeled_string(FILE * f, const char *label, char **value) + { + char *readlabel; + + db_read_labeled_string(f, &readlabel, value); + + if (strcmp(readlabel, label)) { + do_rawlog(LT_ERR, + T("DB: error: Got label '%s', expected label '%s' at line %d"), + readlabel, label, dbline); + longjmp(db_err, 1); + } + } + + /** Read an integer with a given label. + * If the label read is different than the one being checked, the + * database load will abort with an error. + * \param f the file to read from. + * \param label the label that should be read. + * \param value pointer to update to the number that was read. + */ + void + db_read_this_labeled_number(FILE * f, const char *label, int *value) + { + char *readlabel; + char *readvalue; + + db_read_labeled_string(f, &readlabel, &readvalue); + + if (strcmp(readlabel, label)) { + do_rawlog(LT_ERR, + T("DB: error: Got label '%s', expected label '%s' at line %d"), + readlabel, label, dbline); + longjmp(db_err, 1); + } + + *value = parse_integer(readvalue); + } + + /** Read an integer and label. + * \param f the file to read from. + * \param label pointer to update to the address of a static + * buffer containing the label that was read. + * \param value pointer to update to the number that was read. + */ + void + db_read_labeled_number(FILE * f, char **label, int *value) + { + char *readvalue; + db_read_labeled_string(f, label, &readvalue); + *value = parse_integer(readvalue); + } + + /** Read a dbref with a given label. + * If the label read is different than the one being checked, the + * database load will abort with an error. + * \param f the file to read from. + * \param label the label that should be read. + * \param value pointer to update to the dbref that was read. + */ + void + db_read_this_labeled_dbref(FILE * f, const char *label, dbref *val) + { + char *readlabel; + char *readvalue; + + db_read_labeled_string(f, &readlabel, &readvalue); + + if (strcmp(readlabel, label)) { + do_rawlog(LT_ERR, + T("DB: error: Got label '%s', expected label '%s' at line %d"), + readlabel, label, dbline); + longjmp(db_err, 1); + } + *val = qparse_dbref(readvalue); + } + + /** Read a dbref and label. + * \param f the file to read from. + * \param label pointer to update to the address of a static + * buffer containing the label that was read. + * \param value pointer to update to the dbref that was read. + */ + void + db_read_labeled_dbref(FILE * f, char **label, dbref *val) + { + char *readvalue; + db_read_labeled_string(f, label, &readvalue); + *val = qparse_dbref(readvalue); + } + static void db_write_label(FILE * f, char const *l) { ! OUTPUT(fputs(l, f)); ! OUTPUT(putc(' ', f)); } ! void db_write_labeled_string(FILE * f, char const *label, char const *value) { db_write_label(f, label); putstring(f, value); } ! void db_write_labeled_number(FILE * f, char const *label, int value) { OUTPUT(fprintf(f, "%s %d\n", label, value)); } + void + db_write_labeled_dbref(FILE * f, char const *label, dbref value) + { + OUTPUT(fprintf(f, "%s #%d\n", label, value)); + } + /** Write a boolexp to a file in unparsed (text) form. * \param f file pointer to write to. * \param b pointer to boolexp to write. *************** *** 414,420 **** void putboolexp(FILE * f, boolexp b) { ! db_write_labeled_string(f, "key", unparse_boolexp(GOD, b, UB_DBREF)); } /** Write a list of locks to a file. --- 526,532 ---- void putboolexp(FILE * f, boolexp b) { ! db_write_labeled_string(f, " key", unparse_boolexp(GOD, b, UB_DBREF)); } /** Write a list of locks to a file. *************** *** 430,443 **** count++; db_write_labeled_number(f, "lockcount", count); for (ll = l; ll; ll = ll->next) { ! db_write_labeled_string(f, "type", ll->type); ! db_write_labeled_number(f, "creator", L_CREATOR(ll)); ! db_write_labeled_number(f, "flags", L_FLAGS(ll)); putboolexp(f, ll->key); /* putboolexp adds a '\n', so we won't. */ } } /** Write out the basics of an object. * This function writes out the basic information associated with an * object - just about everything but the attributes. --- 542,557 ---- count++; db_write_labeled_number(f, "lockcount", count); for (ll = l; ll; ll = ll->next) { ! db_write_labeled_string(f, " type", ll->type); ! db_write_labeled_dbref(f, " creator", L_CREATOR(ll)); ! db_write_labeled_string(f, " flags", lock_flags_long(ll)); ! db_write_labeled_number(f, " derefs", chunk_derefs(L_KEY(ll))); putboolexp(f, ll->key); /* putboolexp adds a '\n', so we won't. */ } } + /** Write out the basics of an object. * This function writes out the basic information associated with an * object - just about everything but the attributes. *************** *** 448,472 **** static void db_write_obj_basic(FILE * f, dbref i, struct object *o) { ! putstring(f, o->name); ! putref(f, o->location); ! putref(f, o->contents); ! putref(f, o->exits); ! putref(f, o->next); ! putref(f, o->parent); putlocks(f, Locks(i)); ! putref(f, o->owner); ! putref(f, o->zone); ! putref(f, Pennies(i)); ! putref(f, Typeof(i)); ! putstring(f, bits_to_string("FLAG", o->flags, GOD, NOTHING)); ! putstring(f, bits_to_string("POWER", o->powers, GOD, NOTHING)); ! /* Original chat system wrote chat channels to the db here. ! * That's no longer done, they're written to chatdb ! */ ! putref(f, o->warnings); ! putref(f, o->creation_time); ! putref(f, o->modification_time); } /** Write out an object. --- 562,585 ---- static void db_write_obj_basic(FILE * f, dbref i, struct object *o) { ! db_write_labeled_string(f, "name", o->name); ! db_write_labeled_dbref(f, "location", o->location); ! db_write_labeled_dbref(f, "contents", o->contents); ! db_write_labeled_dbref(f, "exits", o->exits); ! db_write_labeled_dbref(f, "next", o->next); ! db_write_labeled_dbref(f, "parent", o->parent); putlocks(f, Locks(i)); ! db_write_labeled_dbref(f, "owner", o->owner); ! db_write_labeled_dbref(f, "zone", o->zone); ! db_write_labeled_number(f, "pennies", Pennies(i)); ! db_write_labeled_number(f, "type", Typeof(i)); ! db_write_labeled_string(f, "flags", ! bits_to_string("FLAG", o->flags, GOD, NOTHING)); ! db_write_labeled_string(f, "powers", ! bits_to_string("POWER", o->powers, GOD, NOTHING)); ! db_write_labeled_string(f, "warnings", unparse_warnings(o->warnings)); ! db_write_labeled_number(f, "created", (int) o->creation_time); ! db_write_labeled_number(f, "modified", (int) o->modification_time); } /** Write out an object. *************** *** 479,496 **** { struct object *o; ALIST *list; o = db + i; db_write_obj_basic(f, i, o); /* write the attribute list */ for (list = o->list; list; list = AL_NEXT(list)) { if (AF_Nodump(list)) continue; ! OUTPUT(fprintf(f, "]%s^%d^%d^%d\n", AL_NAME(list), Owner(AL_CREATOR(list)), ! AL_FLAGS(list), AL_DEREFS(list))); ! putstring(f, atr_value(list)); } - OUTPUT(fprintf(f, "<\n")); return 0; } --- 592,621 ---- { struct object *o; ALIST *list; + int count = 0; + o = db + i; db_write_obj_basic(f, i, o); /* write the attribute list */ + + /* Don't trust AttrCount(thing) for number of attributes to write. */ + for (list = o->list; list; list = AL_NEXT(list)) { + if (AF_Nodump(list)) + continue; + count++; + } + db_write_labeled_number(f, "attrcount", count); + for (list = o->list; list; list = AL_NEXT(list)) { if (AF_Nodump(list)) continue; ! db_write_labeled_string(f, " name", AL_NAME(list)); ! db_write_labeled_dbref(f, " owner", Owner(AL_CREATOR(list))); ! db_write_labeled_string(f, " flags", atrflag_to_string(AL_FLAGS(list))); ! db_write_labeled_number(f, " derefs", AL_DEREFS(list)); ! db_write_labeled_string(f, " value", atr_value(list)); } return 0; } *************** *** 501,506 **** --- 626,633 ---- * +V
* +FLAGS LIST * + * +POWERS LIST + * * ~ * * \endverbatim *************** *** 538,563 **** dbflag += DBF_NEW_FLAGS; dbflag += DBF_NEW_POWERS; dbflag += DBF_POWERS_LOGGED; OUTPUT(fprintf(f, "+V%d\n", dbflag * 256 + 2)); db_write_flags(f); OUTPUT(fprintf(f, "~%d\n", db_top)); for (i = 0; i < db_top; i++) { ! #ifdef WIN32 ! #ifndef __MINGW32__ /* Keep the service manager happy */ if (shutdown_flag && (i & 0xFF) == 0) shutdown_checkpoint(); #endif - #endif if (IsGarbage(i)) continue; OUTPUT(fprintf(f, "!%d\n", i)); db_write_object(f, i); } OUTPUT(fputs(EOD, f)); ! return (db_top); } static void --- 665,693 ---- dbflag += DBF_NEW_FLAGS; dbflag += DBF_NEW_POWERS; dbflag += DBF_POWERS_LOGGED; + dbflag += DBF_LABELS; OUTPUT(fprintf(f, "+V%d\n", dbflag * 256 + 2)); + + db_write_labeled_string(f, "savedtime", show_time(mudtime, 1)); + db_write_flags(f); OUTPUT(fprintf(f, "~%d\n", db_top)); + for (i = 0; i < db_top; i++) { ! #ifdef WIN32SERVICES /* Keep the service manager happy */ if (shutdown_flag && (i & 0xFF) == 0) shutdown_checkpoint(); #endif if (IsGarbage(i)) continue; OUTPUT(fprintf(f, "!%d\n", i)); db_write_object(f, i); } OUTPUT(fputs(EOD, f)); ! return db_top; } static void *************** *** 591,603 **** dbref owner; int flags; int fixmemdb = 0; ! int count; o = db + i; db_write_obj_basic(f, i, o); /* fflush(f); */ /* write the attribute list, scanning */ for (list = o->list; list; list = next) { next = AL_NEXT(list); if (AF_Nodump(list)) --- 721,742 ---- dbref owner; int flags; int fixmemdb = 0; ! int count = 0; ! int attrcount = 0; o = db + i; db_write_obj_basic(f, i, o); /* fflush(f); */ /* write the attribute list, scanning */ + for (list = o->list; list; list = AL_NEXT(list)) { + if (AF_Nodump(list)) + continue; + attrcount++; + } + + db_write_labeled_number(f, "attrcount", count); + for (list = o->list; list; list = next) { next = AL_NEXT(list); if (AF_Nodump(list)) *************** *** 640,646 **** } /* write that info out */ ! OUTPUT(fprintf(f, "]%s^%d^%d\n", name, (int) owner, AL_FLAGS(list))); /* now check the attribute */ strcpy(tbuf1, atr_value(list)); --- 779,788 ---- } /* write that info out */ ! db_write_labeled_string(f, "name", name); ! db_write_labeled_dbref(f, "owner", owner); ! db_write_labeled_string(f, "flags", atrflag_to_string(AL_FLAGS(list))); ! db_write_labeled_number(f, "derefs", AL_DEREFS(list)); /* now check the attribute */ strcpy(tbuf1, atr_value(list)); *************** *** 662,668 **** i); do_rawlog(LT_CHECK, "%s\n", tbuf1); } ! putstring(f, tbuf1); if (flag && fixmemdb) { /* Fix the db in memory */ flags = AL_FLAGS(list); --- 804,810 ---- i); do_rawlog(LT_CHECK, "%s\n", tbuf1); } ! db_write_labeled_string(f, "value", tbuf1); if (flag && fixmemdb) { /* Fix the db in memory */ flags = AL_FLAGS(list); *************** *** 672,678 **** AL_FLAGS(list) = flags; } } - OUTPUT(fprintf(f, "<\n")); return 0; } --- 814,819 ---- *************** *** 716,738 **** dbflag += DBF_LINK_ANYWHERE; dbflag += DBF_NO_STARTUP_FLAG; dbflag += DBF_AF_NODUMP; ! ! OUTPUT(fprintf(f, "+V%d\n", dbflag * 256 + 2)); do_rawlog(LT_CHECK, "PARANOID WRITE BEGINNING...\n"); ! /* print total number of objects at top of file */ OUTPUT(fprintf(f, "~%d\n", db_top)); /* write out each object */ for (i = 0; i < db_top; i++) { ! #ifdef WIN32 ! #ifndef __MINGW32__ /* Keep the service manager happy */ if (shutdown_flag && (i & 0xFF) == 0) shutdown_checkpoint(); #endif - #endif if (IsGarbage(i)) continue; OUTPUT(fprintf(f, "!%d\n", i)); --- 857,882 ---- dbflag += DBF_LINK_ANYWHERE; dbflag += DBF_NO_STARTUP_FLAG; dbflag += DBF_AF_NODUMP; ! dbflag += DBF_NEW_FLAGS; ! dbflag += DBF_NEW_POWERS; ! dbflag += DBF_POWERS_LOGGED; ! dbflag += DBF_LABELS; do_rawlog(LT_CHECK, "PARANOID WRITE BEGINNING...\n"); ! OUTPUT(fprintf(f, "+V%d\n", dbflag * 256 + 2)); ! ! db_write_labeled_string(f, "savedtime", show_time(mudtime, 1)); ! db_write_flags(f); OUTPUT(fprintf(f, "~%d\n", db_top)); /* write out each object */ for (i = 0; i < db_top; i++) { ! #ifdef WIN32SERVICES /* Keep the service manager happy */ if (shutdown_flag && (i & 0xFF) == 0) shutdown_checkpoint(); #endif if (IsGarbage(i)) continue; OUTPUT(fprintf(f, "!%d\n", i)); *************** *** 744,750 **** OUTPUT(fputs(EOD, f)); do_rawlog(LT_CHECK, T("\t...finished at object #%d\n"), i - 1); do_rawlog(LT_CHECK, "END OF PARANOID WRITE.\n"); ! return (db_top); } --- 888,894 ---- OUTPUT(fputs(EOD, f)); do_rawlog(LT_CHECK, T("\t...finished at object #%d\n"), i - 1); do_rawlog(LT_CHECK, "END OF PARANOID WRITE.\n"); ! return db_top; } *************** *** 756,763 **** getref(FILE * f) { static char buf[BUFFER_LEN]; ! fgets(buf, sizeof(buf), f); ! return (atol(buf)); } --- 900,911 ---- getref(FILE * f) { static char buf[BUFFER_LEN]; ! if (!fgets(buf, sizeof(buf), f)) { ! do_rawlog(LT_ERR, T("Unexpected EOF at line %d"), dbline); ! longjmp(db_err, 1); ! } ! dbline++; ! return strtol(buf, NULL, 10); } *************** *** 778,788 **** p = buf; c = fgetc(f); ! if (c != '"') { for (;;) { if ((c == '\0') || (c == EOF) || ((c == '\n') && ((p == buf) || (p[-1] != '\r')))) { *p = '\0'; return buf; } safe_chr(c, buf, &p); --- 926,941 ---- p = buf; c = fgetc(f); ! if (c == EOF) { ! do_rawlog(LT_ERR, T("Unexpected EOF at line %d"), dbline); ! longjmp(db_err, 1); ! } else if (c != '"') { for (;;) { if ((c == '\0') || (c == EOF) || ((c == '\n') && ((p == buf) || (p[-1] != '\r')))) { *p = '\0'; + if (c == '\n') + dbline++; return buf; } safe_chr(c, buf, &p); *************** *** 798,803 **** --- 951,958 ---- /* Get a possible \n, too */ if ((c = fgetc(f)) != '\n') ungetc(c, f); + else + dbline++; } else if (c != '\n') ungetc(c, f); *p = '\0'; *************** *** 824,865 **** boolexp getboolexp(FILE * f, const char *type) { ! char *label, *val; ! get_logical_line(f, &label, &val); return parse_boolexp(GOD, val, type); } /** Read locks for an object. * This function is used for DBF_SPIFFY_LOCKS to read a whole list * of locks from an object and set them. * \param i dbref of the object. * \param f file pointer to read from. */ void ! get_new_locks(dbref i, FILE * f) { ! char *label, *val; dbref creator; int flags; char type[BUFFER_LEN]; boolexp b; ! int count = 0, n; ! get_logical_line(f, &label, &val); ! count = parse_integer(val); for (n = 0; n < count; n++) { /* Name of the lock */ ! get_logical_line(f, &label, &val); strcpy(type, val); ! /* Creator */ ! get_logical_line(f, &label, &val); ! creator = parse_integer(val); ! /* Flags */ ! get_logical_line(f, &label, &val); ! flags = parse_integer(val); /* boolexp */ ! b = getboolexp(f, type); add_lock_raw(creator, i, type, b, flags); } } --- 979,1029 ---- boolexp getboolexp(FILE * f, const char *type) { ! char *val; ! db_read_this_labeled_string(f, "key", &val); return parse_boolexp(GOD, val, type); } + extern PRIV lock_privs[]; + /** Read locks for an object. * This function is used for DBF_SPIFFY_LOCKS to read a whole list * of locks from an object and set them. * \param i dbref of the object. * \param f file pointer to read from. + * \param c number of locks, or -1 if not yet known. */ void ! get_new_locks(dbref i, FILE * f, int c) { ! char *val, *key; dbref creator; int flags; char type[BUFFER_LEN]; boolexp b; ! int count = c, n, derefs = 0; ! if (c < 0) { ! db_read_this_labeled_string(f, "lockcount", &val); ! count = parse_integer(val); ! } for (n = 0; n < count; n++) { /* Name of the lock */ ! db_read_this_labeled_string(f, "type", &val); strcpy(type, val); ! if (globals.indb_flags & DBF_LABELS) { ! db_read_this_labeled_dbref(f, "creator", &creator); ! db_read_this_labeled_string(f, "flags", &val); ! flags = string_to_privs(lock_privs, val, 0); ! db_read_this_labeled_number(f, "derefs", &derefs); ! } else { ! db_read_this_labeled_number(f, "creator", &creator); ! db_read_this_labeled_number(f, "flags", &flags); ! } /* boolexp */ ! db_read_this_labeled_string(f, "key", &key); ! b = parse_boolexp_d(GOD, key, type, derefs); add_lock_raw(creator, i, type, b, flags); } } *************** *** 1019,1051 **** } } ! ! /** Read the object database from a file. ! * This function reads the entire database from a file. See db_write() ! * for some notes about the expected format. * \param f file pointer to read from. ! * \return number of objects in the database. */ ! dbref ! db_read(FILE * f) { int c; dbref i; struct object *o; int temp = 0; time_t temp_time = 0; - int minimum_flags = - DBF_NEW_STRINGS | DBF_TYPE_GARBAGE | DBF_SPLIT_IMMORTAL | DBF_NO_TEMPLE | - DBF_SPIFFY_LOCKS; - - log_mem_check(); - - loading_db = 1; - clear_players(); - db_free(); - globals.indb_flags = 1; for (i = 0;; i++) { /* Loop invariant: we always begin at the beginning of a line. */ errobj = i; --- 1183,1233 ---- } } + extern PRIV attr_privs[]; ! /** Read an attribute list for an object from a file * \param f file pointer to read from. ! * \param i dbref for the attribute list. ! * \param count the number of attributes to read. */ ! void ! db_read_attrs(FILE * f, dbref i, int count) ! { ! char name[ATTRIBUTE_NAME_LIMIT + 1]; ! char value[BUFFER_LEN + 1]; ! dbref owner; ! int derefs; ! int flags; ! char *tmp; ! ! List(i) = NULL; ! ! for (; count > 0; count--) { ! db_read_this_labeled_string(f, "name", &tmp); ! strcpy(name, tmp); ! db_read_this_labeled_dbref(f, "owner", &owner); ! db_read_this_labeled_string(f, "flags", &tmp); ! flags = string_to_privs(attr_privs, tmp, 0); ! db_read_this_labeled_number(f, "derefs", &derefs); ! db_read_this_labeled_string(f, "value", &tmp); ! strcpy(value, tmp); ! atr_new_add(i, name, value, owner, flags, derefs); ! } ! } ! ! /** Read a non-labeled database from a file. ! * \param f the file to read from ! * \return number of objects in the database ! */ ! static dbref ! db_read_oldstyle(FILE * f) { int c; dbref i; struct object *o; int temp = 0; time_t temp_time = 0; for (i = 0;; i++) { /* Loop invariant: we always begin at the beginning of a line. */ errobj = i; *************** *** 1059,1075 **** /* Use the MUSH 2.0 header stuff to see what's in this db */ case '+': c = getc(f); /* Skip the V */ ! if (c == 'V') { ! globals.indb_flags = ((getref(f) - 2) / 256) - 5; ! /* if you want to read in an old-style database, use an earlier ! * patchlevel to upgrade. ! */ ! if (((globals.indb_flags & minimum_flags) != minimum_flags) || ! (globals.indb_flags & DBF_NO_POWERS)) { ! do_rawlog(LT_ERR, T("ERROR: Old database without required dbflags.")); ! return -1; ! } ! } else if (c == 'F') { (void) getstring_noalloc(f); flag_read_all(f, "FLAG"); } else if (c == 'P') { --- 1241,1247 ---- /* Use the MUSH 2.0 header stuff to see what's in this db */ case '+': c = getc(f); /* Skip the V */ ! if (c == 'F') { (void) getstring_noalloc(f); flag_read_all(f, "FLAG"); } else if (c == 'P') { *************** *** 1100,1106 **** o->next = getref(f); o->parent = getref(f); o->locks = NULL; ! get_new_locks(i, f); o->owner = getref(f); o->zone = getref(f); s_Pennies(i, getref(f)); --- 1272,1278 ---- o->next = getref(f); o->parent = getref(f); o->locks = NULL; ! get_new_locks(i, f, -1); o->owner = getref(f); o->zone = getref(f); s_Pennies(i, getref(f)); *************** *** 1251,1256 **** --- 1423,1695 ---- return -1; } } + } + + /** Read the object database from a file. + * This function reads the entire database from a file. See db_write() + * for some notes about the expected format. + * \param f file pointer to read from. + * \return number of objects in the database. + */ + dbref + db_read(FILE * f) + { + int c; + dbref i = 0; + char *tmp; + struct object *o; + int minimum_flags = + DBF_NEW_STRINGS | DBF_TYPE_GARBAGE | DBF_SPLIT_IMMORTAL | DBF_NO_TEMPLE | + DBF_SPIFFY_LOCKS; + + log_mem_check(); + + loading_db = 1; + + clear_players(); + db_free(); + globals.indb_flags = 1; + + c = fgetc(f); + if (c != '+') { + do_rawlog(LT_ERR, T("Database does not start with a version string")); + return -1; + } + c = fgetc(f); + if (c != 'V') { + do_rawlog(LT_ERR, T("Database does not start with a version string")); + return -1; + } + globals.indb_flags = ((getref(f) - 2) / 256) - 5; + /* if you want to read in an old-style database, use an earlier + * patchlevel to upgrade. + */ + if (((globals.indb_flags & minimum_flags) != minimum_flags) || + (globals.indb_flags & DBF_NO_POWERS)) { + do_rawlog(LT_ERR, T("ERROR: Old database without required dbflags.")); + return -1; + } + + if (!(globals.indb_flags & DBF_LABELS)) + return db_read_oldstyle(f); + + db_read_this_labeled_string(f, "savedtime", &tmp); + strcpy(db_timestamp, tmp); + + do_rawlog(LT_ERR, T("Loading database saved on %s UTC"), db_timestamp); + + while ((c = fgetc(f)) != EOF) { + switch (c) { + case '+': + c = fgetc(f); + if (c == 'F') { + (void) getstring_noalloc(f); + flag_read_all(f, "FLAG"); + } else if (c == 'P') { + (void) getstring_noalloc(f); + flag_read_all(f, "POWER"); + } else { + do_rawlog(LT_ERR, T("Unrecognized database format!")); + return -1; + } + break; + case '~': + db_init = (getref(f) * 3) / 2; + init_objdata_htab(db_init); + break; + case '!': + /* Read an object */ + { + char *label, *value; + /* Thre should be an entry in the enum and following table and + switch for each top-level label associated with an + object. Not finding a label is not an error; the default + set in new_object() is used. Finding a label not listed + below is an error. */ + enum known_labels { + LBL_NAME, LBL_LOCATION, LBL_CONTENTS, LBL_EXITS, + LBL_NEXT, LBL_PARENT, LBL_LOCKS, LBL_OWNER, LBL_ZONE, + LBL_PENNIES, LBL_TYPE, LBL_FLAGS, LBL_POWERS, LBL_WARNINGS, + LBL_CREATED, LBL_MODIFIED, LBL_ATTRS, LBL_ERROR + }; + struct label_table { + const char *label; + enum known_labels tag; + }; + struct label_table fields[] = { + {"name", LBL_NAME}, + {"location", LBL_LOCATION}, + {"contents", LBL_CONTENTS}, + {"exits", LBL_EXITS}, + {"next", LBL_NEXT}, + {"parent", LBL_PARENT}, + {"lockcount", LBL_LOCKS}, + {"owner", LBL_OWNER}, + {"zone", LBL_ZONE}, + {"pennies", LBL_PENNIES}, + {"type", LBL_TYPE}, + {"flags", LBL_FLAGS}, + {"powers", LBL_POWERS}, + {"warnings", LBL_WARNINGS}, + {"created", LBL_CREATED}, + {"modified", LBL_MODIFIED}, + {"attrcount", LBL_ATTRS}, + /* Add new label types here. */ + {NULL, LBL_ERROR} + }, *entry; + enum known_labels the_label; + + i = getref(f); + db_grow(i + 1); + o = db + i; + while (1) { + c = fgetc(f); + ungetc(c, f); + /* At the start of another object or the EOD marker */ + if (c == '!' || c == '*') + break; + db_read_labeled_string(f, &label, &value); + the_label = LBL_ERROR; + /* Look up the right enum value in the label table */ + for (entry = fields; entry->label; entry++) { + if (strcmp(entry->label, label) == 0) { + the_label = entry->tag; + break; + } + } + switch (the_label) { + case LBL_NAME: + set_name(i, value); + break; + case LBL_LOCATION: + o->location = qparse_dbref(value); + break; + case LBL_CONTENTS: + o->contents = qparse_dbref(value); + break; + case LBL_EXITS: + o->exits = qparse_dbref(value); + break; + case LBL_NEXT: + o->next = qparse_dbref(value); + break; + case LBL_PARENT: + o->parent = qparse_dbref(value); + break; + case LBL_LOCKS: + get_new_locks(i, f, parse_integer(value)); + break; + case LBL_OWNER: + o->owner = qparse_dbref(value); + break; + case LBL_ZONE: + o->zone = qparse_dbref(value); + break; + case LBL_PENNIES: + s_Pennies(i, parse_integer(value)); + break; + case LBL_TYPE: + o->type = parse_integer(value); + switch (Typeof(i)) { + case TYPE_PLAYER: + current_state.players++; + current_state.garbage--; + break; + case TYPE_THING: + current_state.things++; + current_state.garbage--; + break; + case TYPE_EXIT: + current_state.exits++; + current_state.garbage--; + break; + case TYPE_ROOM: + current_state.rooms++; + current_state.garbage--; + break; + } + break; + case LBL_FLAGS: + o->flags = string_to_bits("FLAG", value); + /* Clear the GOING flags. If it was scheduled for destruction + * when the db was saved, it gets a reprieve. + */ + clear_flag_internal(i, "GOING"); + clear_flag_internal(i, "GOING_TWICE"); + break; + case LBL_POWERS: + o->powers = string_to_bits("POWER", value); + break; + case LBL_WARNINGS: + o->warnings = parse_warnings(NOTHING, value); + break; + case LBL_CREATED: + o->creation_time = (time_t) parse_integer(value); + break; + case LBL_MODIFIED: + o->modification_time = (time_t) parse_integer(value); + break; + case LBL_ATTRS: + { + int attrcount = parse_integer(value); + db_read_attrs(f, i, attrcount); + } + break; + case LBL_ERROR: + default: + do_rawlog(LT_ERR, T("Unrecognized field '%s' in object #%d"), + label, i); + return -1; + } + } + if (IsPlayer(i) && (strlen(o->name) > (size_t) PLAYER_NAME_LIMIT)) { + char buff[BUFFER_LEN + 1]; /* The name plus a NUL */ + strncpy(buff, o->name, PLAYER_NAME_LIMIT); + buff[PLAYER_NAME_LIMIT] = '\0'; + set_name(i, buff); + do_rawlog(LT_CHECK, + T + (" * Name of #%d is longer than the maximum, truncating.\n"), + i); + } else if (!IsPlayer(i) && (strlen(o->name) > OBJECT_NAME_LIMIT)) { + char buff[OBJECT_NAME_LIMIT + 1]; /* The name plus a NUL */ + strncpy(buff, o->name, OBJECT_NAME_LIMIT); + buff[OBJECT_NAME_LIMIT] = '\0'; + set_name(i, buff); + do_rawlog(LT_CHECK, + T + (" * Name of #%d is longer than the maximum, truncating.\n"), + i); + } + if (IsPlayer(i)) { + add_player(i, NULL); + clear_flag_internal(i, "CONNECTED"); + } + } + break; + case '*': + { + char buff[80]; + ungetc('*', f); + fgets(buff, sizeof buff, f); + if (strcmp(buff, EOD) != 0) { + do_rawlog(LT_ERR, T("ERROR: No end of dump after object #%d"), i - 1); + return -1; + } else { + do_rawlog(LT_ERR, "READING: done"); + loading_db = 0; + fix_free_list(); + dbck(); + log_mem_check(); + return db_top; + } + } + default: + do_rawlog(LT_ERR, T("ERROR: failed object %d"), i); + return -1; + } + } + return -1; } static void *** 1_7_7.1196/src/cque.c Wed, 21 Jul 2004 15:30:20 -0500 dunemush (pennmush/c/28_cque.c 1.36.1.5.1.1.1.1.1.1.1.2.1.6.1.26 660) --- 1_7_7.1227(w)/src/cque.c Tue, 02 Nov 2004 11:00:10 -0600 dunemush (pennmush/c/28_cque.c 1.36.1.5.1.1.1.1.1.1.1.2.1.6.1.29 660) *************** *** 185,191 **** pay_queue(dbref player, const char *command) { int estcost; ! estcost = QUEUE_COST + ((get_random_long(0, QUEUE_LOSS - 1) == 0) ? 1 : 0); if (!payfor(player, estcost)) { notify(Owner(player), T("Not enough money to queue command.")); return 0; --- 185,193 ---- pay_queue(dbref player, const char *command) { int estcost; ! estcost = ! QUEUE_COST + ! (QUEUE_LOSS ? ((get_random_long(0, QUEUE_LOSS - 1) == 0) ? 1 : 0) : 0); if (!payfor(player, estcost)) { notify(Owner(player), T("Not enough money to queue command.")); return 0; *************** *** 937,943 **** default: if (!quick) { ! if (all == QUEUE_ALL) notify(player, T("Queue for : all")); else notify_format(player, T("Queue for : %s"), Name(victim)); --- 939,945 ---- default: if (!quick) { ! if (all) notify(player, T("Queue for : all")); else notify_format(player, T("Queue for : %s"), Name(victim)); *** 1_7_7.1196/src/conf.c Thu, 15 Jul 2004 14:37:11 -0500 dunemush (pennmush/c/31_conf.c 1.41.2.3.1.3.1.2.1.15.1.1.1.1.1.1.1.40 660) --- 1_7_7.1227(w)/src/conf.c Tue, 02 Nov 2004 11:00:10 -0600 dunemush (pennmush/c/31_conf.c 1.41.2.3.1.3.1.2.1.15.1.1.1.1.1.1.1.41 660) *************** *** 342,348 **** , {"use_quota", cf_bool, &options.use_quota, 2, 0, "limits"} , - {"max_channels", cf_int, &options.max_channels, 1000, 0, "chat"} , {"max_player_chans", cf_int, &options.max_player_chans, 100, 0, "chat"} --- 342,347 ---- *** 1_7_7.1196/src/command.c Tue, 24 Aug 2004 09:41:40 -0500 dunemush (pennmush/c/36_command.c 1.56.1.1.1.1.1.1.1.2.1.1.1.1.1.5.1.2.1.1.1.1.1.2.1.3.1.10.1.1.3.71 660) --- 1_7_7.1227(w)/src/command.c Tue, 02 Nov 2004 11:00:10 -0600 dunemush (pennmush/c/36_command.c 1.56.1.1.1.1.1.1.1.2.1.1.1.1.1.5.1.2.1.1.1.1.1.2.1.3.1.10.1.1.3.74.1.1 660) *************** *** 280,285 **** --- 280,286 ---- {"@ZEMIT", NULL, cmd_zemit, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_NOGAGGED, 0, 0}, + {"BUY", NULL, cmd_buy, CMD_T_ANY | CMD_T_NOGAGGED, 0, 0}, {"BRIEF", NULL, cmd_brief, CMD_T_ANY, 0, 0}, {"DESERT", NULL, cmd_desert, CMD_T_PLAYER | CMD_T_THING, 0, 0}, {"DISMISS", NULL, cmd_dismiss, CMD_T_PLAYER | CMD_T_THING, 0, 0}, *************** *** 432,437 **** --- 433,439 ---- cmd = (COMMAND_INFO *) mush_malloc(sizeof(COMMAND_INFO), "command"); memset(cmd, 0, sizeof(COMMAND_INFO)); cmd->name = name; + cmd->restrict_message = NULL; cmd->func = func; cmd->type = type; cmd->flagmask = flagmask; *************** *** 907,912 **** --- 909,928 ---- case EMIT_TOKEN: replacer = "@EMIT"; break; + case CHAT_TOKEN: + #ifdef CHAT_TOKEN_ALIAS + case CHAT_TOKEN_ALIAS: + #endif + /* parse_chat() destructively modifies the command to replace + * the first space with a '=' if the command is an actual + * chat command */ + if (parse_chat(player, p + 1) && command_check_byname(player, "@CHAT")) { + /* This is a "+chan foo" chat style + * We set noevtoken to keep its noeval way, and + * set the cmd to allow @hook. */ + replacer = "@CHAT"; + noevtoken = 1; + } } if (replacer) { *************** *** 917,932 **** * to the default parsing if the syntax we're given doesn't * quite match. */ ! if (*p == CHAT_TOKEN ! #ifdef CHAT_TOKEN_ALIAS ! || *p == CHAT_TOKEN_ALIAS ! #endif ! ) { ! if (command_check_byname(player, "@chat") && parse_chat(player, p + 1)) { ! command_parse_free_args; ! return NULL; ! } ! } else if (*p == '#') { if (!Gagged(player) && Mobile(player) && force_by_number(player, string)) { command_parse_free_args; --- 933,939 ---- * to the default parsing if the syntax we're given doesn't * quite match. */ ! if (*p == '#') { if (!Gagged(player) && Mobile(player) && force_by_number(player, string)) { command_parse_free_args; *************** *** 1248,1253 **** --- 1255,1261 ---- { COMMAND_INFO *command; struct command_perms_t *c; + char *message; int clear; FLAG *mask; FLAG *powers; *************** *** 1257,1262 **** --- 1265,1281 ---- !(command = command_find(name))) return 0; + if (command->restrict_message) { + mush_free((Malloc_t) command->restrict_message, "cmd_restrict_message"); + command->restrict_message = NULL; + } + message = strchr(restriction, '"'); + if (message) { + *(message++) = '\0'; + if ((message = trim_space_sep(message, ' ')) && *message) + command->restrict_message = mush_strdup(message, "cmd_restrict_message"); + } + while (restriction && *restriction) { if ((tp = strchr(restriction, ' '))) *tp++ = '\0'; *************** *** 1592,1617 **** command_check(dbref player, COMMAND_INFO *cmd) { int ok; int check_flags, check_powers; /* If disabled, return silently */ if (cmd->type & CMD_T_DISABLED) return 0; if ((cmd->type & CMD_T_NOGAGGED) && Gagged(player)) { ! notify(player, T("You cannot do that while gagged.")); ! return 0; } if ((cmd->type & CMD_T_NOFIXED) && Fixed(player)) { ! notify(player, T("You cannot do that while fixed.")); ! return 0; } if ((cmd->type & CMD_T_NOGUEST) && Guest(player)) { ! notify(player, T("Guests cannot do that.")); ! return 0; } if ((cmd->type & CMD_T_GOD) && (!God(player))) { ! notify(player, T("Only God can do that.")); ! return 0; } switch (Typeof(player)) { case TYPE_ROOM: --- 1611,1637 ---- command_check(dbref player, COMMAND_INFO *cmd) { int ok; + char *mess = NULL; int check_flags, check_powers; /* If disabled, return silently */ if (cmd->type & CMD_T_DISABLED) return 0; if ((cmd->type & CMD_T_NOGAGGED) && Gagged(player)) { ! mess = T("You cannot do that while gagged."); ! goto send_error; } if ((cmd->type & CMD_T_NOFIXED) && Fixed(player)) { ! mess = T("You cannot do that while fixed."); ! goto send_error; } if ((cmd->type & CMD_T_NOGUEST) && Guest(player)) { ! mess = T("Guests cannot do that."); ! goto send_error; } if ((cmd->type & CMD_T_GOD) && (!God(player))) { ! mess = T("Only God can do that."); ! goto send_error; } switch (Typeof(player)) { case TYPE_ROOM: *************** *** 1630,1637 **** ok = 0; } if (!ok) { ! notify(player, T("Permission denied, command is type-restricted.")); ! return 0; } /* A command can specify required flags or powers, and if * any match, the player is ok to do the command. --- 1650,1657 ---- ok = 0; } if (!ok) { ! mess = T("Permission denied, command is type-restricted."); ! goto send_error; } /* A command can specify required flags or powers, and if * any match, the player is ok to do the command. *************** *** 1644,1652 **** ok = !!(has_any_flags_by_mask(player, cmd->flagmask)); if (!ok && check_powers) ok = !!(has_any_powers_by_mask(player, cmd->powers)); ! if (!ok) ! notify(player, T("Permission denied.")); return ok; } /** Determine whether a player can use a command. --- 1664,1681 ---- ok = !!(has_any_flags_by_mask(player, cmd->flagmask)); if (!ok && check_powers) ok = !!(has_any_powers_by_mask(player, cmd->powers)); ! if (!ok) { ! mess = T("Permission denied."); ! goto send_error; ! } return ok; + + send_error: + if (cmd->restrict_message) + notify(player, cmd->restrict_message); + else if (mess) + notify(player, mess); + return 0; } /** Determine whether a player can use a command. *** 1_7_7.1196/src/cmds.c Tue, 24 Aug 2004 09:41:40 -0500 dunemush (pennmush/c/37_cmds.c 1.33.1.1.1.2.1.2.2.3.1.1.1.2.1.1.1.3.1.8.1.1.2.2.2.20.1.3.1.7.1.2.1.20.1.1 660) --- 1_7_7.1227(w)/src/cmds.c Tue, 02 Nov 2004 11:00:10 -0600 dunemush (pennmush/c/37_cmds.c 1.33.1.1.1.2.1.2.2.3.1.1.1.2.1.1.1.3.1.8.1.1.2.2.2.20.1.3.1.7.1.2.1.20.1.2 660) *************** *** 992,997 **** --- 992,1030 ---- do_get(player, arg_left); } + COMMAND (cmd_buy) { + char *from = NULL; + char *forwhat = NULL; + int price = -1; + + upcasestr(arg_left); + + from = strstr(arg_left, " FROM "); + forwhat = strstr(arg_left, " FOR "); + if (from) { + *from = '\0'; + from += 6; + } + if (forwhat) { + *forwhat = '\0'; + forwhat += 5; + } + if (forwhat && !is_strict_integer(forwhat)) { + notify(player, T("Buy for WHAT price?")); + return; + } else if (forwhat) { + price = parse_integer(forwhat); + if (price < 0) { + notify(player, T("You can't buy things by taking money.")); + return; + } + } + + if (from) + from = trim_space_sep(from, ' '); + do_buy(player, arg_left, from, price); + } + COMMAND (cmd_give) { do_give(player, arg_left, arg_right, (SW_ISSET(sw, SWITCH_SILENT))); } *** 1_7_7.1196/src/bsd.c Mon, 23 Aug 2004 18:24:28 -0500 dunemush (pennmush/c/38_bsd.c 1.58.1.11.1.2.1.5.1.7.1.14.1.13.1.9.1.4.1.2.1.12.1.1.1.1.1.2.1.1.1.13.1.1.1.1.1.1.1.1.1.1.1.3.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.3.1.8.2.1.1.1.1.1.1.1.1.2.1.1.1.1.1.1.1.1.1.1.1.1.1.9.1.1.1.48.1.1.1.7 660) --- 1_7_7.1227(w)/src/bsd.c Tue, 02 Nov 2004 11:00:10 -0600 dunemush (pennmush/c/38_bsd.c 1.58.1.11.1.2.1.5.1.7.1.14.1.13.1.9.1.4.1.2.1.12.1.1.1.1.1.2.1.1.1.13.1.1.1.1.1.1.1.1.1.1.1.3.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.3.1.8.2.1.1.1.1.1.1.1.1.2.1.1.1.1.1.1.1.1.1.1.1.1.1.9.1.1.1.48.1.1.1.14 660) *************** *** 28,36 **** #define EWOULDBLOCK WSAEWOULDBLOCK #define MAXHOSTNAMELEN 32 #define LC_MESSAGES 6 - #ifndef __MINGW32__ - void shutdown_checkpoint(void); - #endif #else /* !WIN32 */ #ifdef I_SYS_FILE #include --- 28,33 ---- *************** *** 122,127 **** --- 119,125 ---- #include "extmail.h" #include "attrib.h" #include "game.h" + #include "dbio.h" #include "confmagic.h" #ifdef HAS_WAITPID /** What does wait*() return? */ *************** *** 328,334 **** static void init_rlimit(void); #endif #ifndef BOOLEXP_DEBUGGING ! #ifdef WIN32 void mainthread(int argc, char **argv); #else int main(int argc, char **argv); --- 326,333 ---- static void init_rlimit(void); #endif #ifndef BOOLEXP_DEBUGGING ! #ifdef WIN32SERVICES ! void shutdown_checkpoint(void); void mainthread(int argc, char **argv); #else int main(int argc, char **argv); *************** *** 495,501 **** #endif #ifndef BOOLEXP_DEBUGGING ! #if defined(WIN32) && !defined(__MINGW32__) /* Under WIN32, MUSH is a "service", so we just start a thread here. * The real "main" is in win32/services.c */ --- 494,500 ---- #endif #ifndef BOOLEXP_DEBUGGING ! #ifdef WIN32SERVICES /* Under WIN32, MUSH is a "service", so we just start a thread here. * The real "main" is in win32/services.c */ *************** *** 509,515 **** */ int main(int argc, char **argv) ! #endif /* WIN32 */ { #ifdef AUTORESTART FILE *id; --- 508,514 ---- */ int main(int argc, char **argv) ! #endif /* WIN32SERVICES */ { #ifdef AUTORESTART FILE *id; *************** *** 720,740 **** #endif /* someone has told us to shut down */ ! #ifdef WIN32 ! #ifndef __MINGW32__ /* Keep service manager happy */ shutdown_checkpoint(); #endif - #endif shutdown_queues(); ! #ifdef WIN32 ! #ifndef __MINGW32__ /* Keep service manager happy */ shutdown_checkpoint(); #endif - #endif close_sockets(); sql_shutdown(); --- 719,735 ---- #endif /* someone has told us to shut down */ ! #ifdef WIN32SERVICES /* Keep service manager happy */ shutdown_checkpoint(); #endif shutdown_queues(); ! #ifdef WIN32SERVICES /* Keep service manager happy */ shutdown_checkpoint(); #endif close_sockets(); sql_shutdown(); *************** *** 743,754 **** kill_info_slave(); #endif ! #ifdef WIN32 ! #ifndef __MINGW32__ /* Keep service manager happy */ shutdown_checkpoint(); #endif - #endif dump_database(); --- 738,747 ---- kill_info_slave(); #endif ! #ifdef WIN32SERVICES /* Keep service manager happy */ shutdown_checkpoint(); #endif dump_database(); *************** *** 766,777 **** fflush(stderr); #endif ! #ifdef WIN32 ! #ifndef __MINGW32__ /* Keep service manager happy */ shutdown_checkpoint(); #endif - #endif #ifdef HAS_GETRUSAGE rusage_stats(); --- 759,768 ---- fflush(stderr); #endif ! #ifdef WIN32SERVICES /* Keep service manager happy */ shutdown_checkpoint(); #endif #ifdef HAS_GETRUSAGE rusage_stats(); *************** *** 788,794 **** closesocket(sock); #ifdef WIN32 ! #ifndef __MINGW32__ shutdown_checkpoint(); #endif WSACleanup(); /* clean up */ --- 779,785 ---- closesocket(sock); #ifdef WIN32 ! #ifdef WIN32SERVICES shutdown_checkpoint(); #endif WSACleanup(); /* clean up */ *************** *** 3356,3362 **** show_time(globals.first_start_time, 0))); queue_string_eol(call_by, tprintf("Connected: %d", count)); queue_string_eol(call_by, tprintf("Size: %d", db_top)); ! queue_string_eol(call_by, tprintf("Version: %sp%s", VERSION, PATCHLEVEL)); #ifdef PATCHES queue_string_eol(call_by, tprintf("Patches: %s", PATCHES)); #endif --- 3347,3354 ---- show_time(globals.first_start_time, 0))); queue_string_eol(call_by, tprintf("Connected: %d", count)); queue_string_eol(call_by, tprintf("Size: %d", db_top)); ! queue_string_eol(call_by, ! tprintf("Version: PennMUSH %sp%s", VERSION, PATCHLEVEL)); #ifdef PATCHES queue_string_eol(call_by, tprintf("Patches: %s", PATCHES)); #endif *************** *** 4079,4089 **** { DESC *d; int first; ! int powered = (*called_as == 'L'); first = 1; DESC_ITER_CONN(d) { ! if (!Hidden(d) || (powered && Priv_Who(executor))) { if (first) first = 0; else --- 4071,4099 ---- { DESC *d; int first; ! dbref victim; ! int powered = ((*called_as == 'L') && Priv_Who(executor)); first = 1; + + if (nargs && args