Two bug fixes (Thanks Slicer) in CAP (utils.c) and delete_object (genobj.c)

This commit is contained in:
JamDog 2009-03-08 20:18:27 +00:00
parent b35073602f
commit 2d52e5cb67
3 changed files with 215 additions and 203 deletions

View file

@ -35,6 +35,9 @@ export (QQ's a zone into a tarball)t
Xlist (mlist, olist, rlist, zlist, slist, tlist, qlist) Xlist (mlist, olist, rlist, zlist, slist, tlist, qlist)
(lots of major bugfixes too) (lots of major bugfixes too)
tbaMUD 3.59 tbaMUD 3.59
[Mar 08 2009] - Jamdog
Fixed a possible crash bug in delete_object (genobj.c) (Thanks Slicer)
CAP function now recognises both preceeding color codes and ANSI codes (Thanks Slicer)
[Mar 07 2009] - Jamdog [Mar 07 2009] - Jamdog
Fixed a bug in find_shop (shop.c) and real_shop (genshp.c) (Thanks Slicer) Fixed a bug in find_shop (shop.c) and real_shop (genshp.c) (Thanks Slicer)
[Feb 25 2009] - Jamdog [Feb 25 2009] - Jamdog

View file

@ -43,9 +43,9 @@ obj_rnum add_object(struct obj_data *newobj, obj_vnum ovnum)
return found; return found;
} }
/* Fix all existing objects to have these values. We need to run through each /* Fix all existing objects to have these values. We need to run through each
* and every object currently in the game to see which ones are pointing to * and every object currently in the game to see which ones are pointing to
* this prototype. If object is pointing to this prototype, then we need to * this prototype. If object is pointing to this prototype, then we need to
* replace it with the new one. */ * replace it with the new one. */
static int update_all_objects(struct obj_data *refobj) static int update_all_objects(struct obj_data *refobj)
{ {
@ -78,8 +78,8 @@ static int update_all_objects(struct obj_data *refobj)
return count; return count;
} }
/* Adjust the internal values of other objects as if something was inserted at /* Adjust the internal values of other objects as if something was inserted at
* the given array index. Might also be useful to make 'holes' in the array * the given array index. Might also be useful to make 'holes' in the array
* for some reason. */ * for some reason. */
obj_rnum adjust_objects(obj_rnum refpt) obj_rnum adjust_objects(obj_rnum refpt)
{ {
@ -128,8 +128,8 @@ obj_rnum adjust_objects(obj_rnum refpt)
return refpt; return refpt;
} }
/* Function handle the insertion of an object within the prototype framework. /* Function handle the insertion of an object within the prototype framework.
* Note that this does not adjust internal values of other objects, use * Note that this does not adjust internal values of other objects, use
* add_object() for that. */ * add_object() for that. */
obj_rnum insert_object(struct obj_data *obj, obj_vnum ovnum) obj_rnum insert_object(struct obj_data *obj, obj_vnum ovnum)
{ {
@ -374,12 +374,12 @@ int delete_object(obj_rnum rnum)
{ {
obj_rnum i; obj_rnum i;
zone_rnum zrnum; zone_rnum zrnum;
struct obj_data *obj, *tmp; struct obj_data *obj, *tmp, *next_obj;
int shop, j, zone, cmd_no; int shop, j, zone, cmd_no;
if (rnum == NOTHING || rnum > top_of_objt) if (rnum == NOTHING || rnum > top_of_objt)
return NOTHING; return NOTHING;
obj = &obj_proto[rnum]; obj = &obj_proto[rnum];
zrnum = real_zone_by_thing(GET_OBJ_VNUM(obj)); zrnum = real_zone_by_thing(GET_OBJ_VNUM(obj));
@ -387,7 +387,8 @@ int delete_object(obj_rnum rnum)
/* This is something you might want to read about in the logs. */ /* This is something you might want to read about in the logs. */
log("GenOLC: delete_object: Deleting object #%d (%s).", GET_OBJ_VNUM(obj), obj->short_description); log("GenOLC: delete_object: Deleting object #%d (%s).", GET_OBJ_VNUM(obj), obj->short_description);
for (tmp = object_list; tmp; tmp = tmp->next) { for (tmp = object_list; tmp; tmp = next_obj) {
next_obj = tmp->next;
if (tmp->item_number != obj->item_number) if (tmp->item_number != obj->item_number)
continue; continue;

View file

@ -1,13 +1,13 @@
/** /**
* @file utils.c * @file utils.c
* Various utility functions used within the core mud code. * Various utility functions used within the core mud code.
* *
* Part of the core tbaMUD source code distribution, which is a derivative * Part of the core tbaMUD source code distribution, which is a derivative
* of, and continuation of, CircleMUD. * of, and continuation of, CircleMUD.
* *
* All rights reserved. See license for complete information. * All rights reserved. See license for complete information.
* Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University * Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University
* CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991. * CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991.
*/ */
#include "conf.h" #include "conf.h"
@ -37,19 +37,19 @@ int rand_number(int from, int to)
log("SYSERR: rand_number() should be called with lowest, then highest. (%d, %d), not (%d, %d).", from, to, to, from); log("SYSERR: rand_number() should be called with lowest, then highest. (%d, %d), not (%d, %d).", from, to, to, from);
} }
/* This should always be of the form: ((float)(to - from + 1) * rand() / /* This should always be of the form: ((float)(to - from + 1) * rand() /
* (float)(RAND_MAX + from) + from); If you are using rand() due to historical * (float)(RAND_MAX + from) + from); If you are using rand() due to historical
* non-randomness of the lower bits in older implementations. We always use * non-randomness of the lower bits in older implementations. We always use
* circle_random() though, which shouldn't have that problem. Mean and * circle_random() though, which shouldn't have that problem. Mean and
* standard deviation of both are identical (within the realm of statistical * standard deviation of both are identical (within the realm of statistical
* identity) if the rand() implementation is non-broken. */ * identity) if the rand() implementation is non-broken. */
return ((circle_random() % (to - from + 1)) + from); return ((circle_random() % (to - from + 1)) + from);
} }
/** Simulates a single dice roll from one to many of a certain sized die. /** Simulates a single dice roll from one to many of a certain sized die.
* @param num The number of dice to roll. * @param num The number of dice to roll.
* @param size The number of sides each die has, and hence the number range * @param size The number of sides each die has, and hence the number range
* of the die. * of the die.
* @retval int The sum of all the dice rolled. A random number. */ * @retval int The sum of all the dice rolled. A random number. */
int dice(int num, int size) int dice(int num, int size)
{ {
@ -64,7 +64,7 @@ int dice(int num, int size)
return (sum); return (sum);
} }
/** Return the smaller number. Original note: Be wary of sign issues with this. /** Return the smaller number. Original note: Be wary of sign issues with this.
* @param a The first number. * @param a The first number.
* @param b The second number. * @param b The second number.
* @retval int The smaller of the two, a or b. */ * @retval int The smaller of the two, a or b. */
@ -73,7 +73,7 @@ int MIN(int a, int b)
return (a < b ? a : b); return (a < b ? a : b);
} }
/** Return the larger number. Original note: Be wary of sign issues with this. /** Return the larger number. Original note: Be wary of sign issues with this.
* @param a The first number. * @param a The first number.
* @param b The second number. * @param b The second number.
* @retval int The larger of the two, a or b. */ * @retval int The larger of the two, a or b. */
@ -82,26 +82,34 @@ int MAX(int a, int b)
return (a > b ? a : b); return (a > b ? a : b);
} }
/** Used to capitalize a string. Will not change any mud specific color codes. /** Used to capitalize a string. Will not change any mud specific color codes.
* @param txt The string to capitalize. * @param txt The string to capitalize.
* @retval char* Pointer to the capitalized string. */ * @retval char* Pointer to the capitalized string. */
char *CAP(char *txt) char *CAP(char *txt)
{ {
char *p = txt; char *p = txt;
while (*p == '@' && *(p+1)) /* Skip all preceeding color codes and ANSI codes */
p += 2; while ((*p == '@' && *(p+1)) || (*p == '\x1B' && *(p+1) == '[')) {
if (*p == '@') p += 2; /* Skip @ sign and color letter/number */
else {
p += 2; /* Skip the CSI section of the ANSI code */
while (*p && !isalpha(*p)) p++; /* Skip until a 'letter' is found */
if (*p) p++; /* Skip the letter */
}
}
if (*p) if (*p)
*p = UPPER(*p); *p = UPPER(*p);
return (txt); return (txt);
} }
#if !defined(HAVE_STRLCPY) #if !defined(HAVE_STRLCPY)
/** A 'strlcpy' function in the same fashion as 'strdup' below. This copies up /** A 'strlcpy' function in the same fashion as 'strdup' below. This copies up
* to totalsize - 1 bytes from the source string, placing them and a trailing * to totalsize - 1 bytes from the source string, placing them and a trailing
* NUL into the destination string. Returns the total length of the string it * NUL into the destination string. Returns the total length of the string it
* tried to copy, not including the trailing NUL. So a '>= totalsize' test * tried to copy, not including the trailing NUL. So a '>= totalsize' test
* says it was truncated. (Note that you may have _expected_ truncation * says it was truncated. (Note that you may have _expected_ truncation
* because you only wanted a few characters from the source string.) Portable * because you only wanted a few characters from the source string.) Portable
* function, in case your system does not have strlcpy. */ * function, in case your system does not have strlcpy. */
size_t strlcpy(char *dest, const char *source, size_t totalsize) size_t strlcpy(char *dest, const char *source, size_t totalsize)
@ -136,8 +144,8 @@ void prune_crlf(char *txt)
} }
#ifndef str_cmp #ifndef str_cmp
/** a portable, case-insensitive version of strcmp(). Returns: 0 if equal, > 0 /** a portable, case-insensitive version of strcmp(). Returns: 0 if equal, > 0
* if arg1 > arg2, or < 0 if arg1 < arg2. Scan until strings are found * if arg1 > arg2, or < 0 if arg1 < arg2. Scan until strings are found
* different or we reach the end of both. */ * different or we reach the end of both. */
int str_cmp(const char *arg1, const char *arg2) int str_cmp(const char *arg1, const char *arg2)
{ {
@ -157,8 +165,8 @@ int str_cmp(const char *arg1, const char *arg2)
#endif #endif
#ifndef strn_cmp #ifndef strn_cmp
/** a portable, case-insensitive version of strncmp(). Returns: 0 if equal, > 0 /** a portable, case-insensitive version of strncmp(). Returns: 0 if equal, > 0
* if arg1 > arg2, or < 0 if arg1 < arg2. Scan until strings are found * if arg1 > arg2, or < 0 if arg1 < arg2. Scan until strings are found
* different, the end of both, or n is reached. */ * different, the end of both, or n is reached. */
int strn_cmp(const char *arg1, const char *arg2, int n) int strn_cmp(const char *arg1, const char *arg2, int n)
{ {
@ -177,12 +185,12 @@ int strn_cmp(const char *arg1, const char *arg2, int n)
} }
#endif #endif
/** New variable argument log() function; logs messages to disk. /** New variable argument log() function; logs messages to disk.
* Works the same as the old for previously written code but is very nice * Works the same as the old for previously written code but is very nice
* if new code wishes to implment printf style log messages without the need * if new code wishes to implment printf style log messages without the need
* to make prior sprintf calls. * to make prior sprintf calls.
* @param format The message to log. Standard printf formatting and variable * @param format The message to log. Standard printf formatting and variable
* arguments are allowed. * arguments are allowed.
* @param args The comma delimited, variable substitutions to make in str. */ * @param args The comma delimited, variable substitutions to make in str. */
void basic_mud_vlog(const char *format, va_list args) void basic_mud_vlog(const char *format, va_list args)
{ {
@ -210,7 +218,7 @@ void basic_mud_vlog(const char *format, va_list args)
* any calls to plain old log() have been redirected, via macro, to this * any calls to plain old log() have been redirected, via macro, to this
* function. * function.
* @param format The message to log. Standard printf formatting and variable * @param format The message to log. Standard printf formatting and variable
* arguments are allowed. * arguments are allowed.
* @param ... The comma delimited, variable substitutions to make in str. */ * @param ... The comma delimited, variable substitutions to make in str. */
void basic_mud_log(const char *format, ...) void basic_mud_log(const char *format, ...)
{ {
@ -222,7 +230,7 @@ void basic_mud_log(const char *format, ...)
} }
/** Essentially the touch command. Create an empty file or update the modified /** Essentially the touch command. Create an empty file or update the modified
* time of a file. * time of a file.
* @param path The filepath to "touch." This filepath is relative to the /lib * @param path The filepath to "touch." This filepath is relative to the /lib
* directory relative to the root of the mud distribution. * directory relative to the root of the mud distribution.
* @retval int 0 on a success, -1 on a failure; standard system call exit * @retval int 0 on a success, -1 on a failure; standard system call exit
@ -240,15 +248,15 @@ int touch(const char *path)
} }
} }
/** Log mud messages to a file & to online imm's syslogs. /** Log mud messages to a file & to online imm's syslogs.
* @param type The minimum syslog level that needs be set to see this message. * @param type The minimum syslog level that needs be set to see this message.
* OFF, BRF, NRM and CMP are the values from lowest to highest. Using mudlog * OFF, BRF, NRM and CMP are the values from lowest to highest. Using mudlog
* with type = OFF should be avoided as every imm will see the message even * with type = OFF should be avoided as every imm will see the message even
* if they have syslog turned off. * if they have syslog turned off.
* @param level Minimum character level needed to see this message. * @param level Minimum character level needed to see this message.
* @param file TRUE log this to the syslog file, FALSE do not log this to disk. * @param file TRUE log this to the syslog file, FALSE do not log this to disk.
* @param str The message to log. Standard printf formatting and variable * @param str The message to log. Standard printf formatting and variable
* arguments are allowed. * arguments are allowed.
* @param ... The comma delimited, variable substitutions to make in str. */ * @param ... The comma delimited, variable substitutions to make in str. */
void mudlog(int type, int level, int file, const char *str, ...) void mudlog(int type, int level, int file, const char *str, ...)
{ {
@ -290,19 +298,19 @@ void mudlog(int type, int level, int file, const char *str, ...)
/** Take a bitvector and return a human readable /** Take a bitvector and return a human readable
* description of which bits are set in it. * description of which bits are set in it.
* @pre The final element in the names array must contain a one character * @pre The final element in the names array must contain a one character
* string consisting of a single newline character "\n". Caller of function is * string consisting of a single newline character "\n". Caller of function is
* responsible for creating the memory buffer for the result string. * responsible for creating the memory buffer for the result string.
* @param[in] bitvector The bitvector to test for set bits. * @param[in] bitvector The bitvector to test for set bits.
* @param[in] names An array of human readable strings describing each possible * @param[in] names An array of human readable strings describing each possible
* bit. The final element in this array must be a string made of a single * bit. The final element in this array must be a string made of a single
* newline character (eg "\n"). * newline character (eg "\n").
* If you don't have a 'const' array for the names param, cast it as such. * If you don't have a 'const' array for the names param, cast it as such.
* @param[out] result Holds the names of the set bits in bitvector. The bit * @param[out] result Holds the names of the set bits in bitvector. The bit
* names will be delimited by a single space. * names will be delimited by a single space.
* Caller of sprintbit is responsible for creating the buffer for result. * Caller of sprintbit is responsible for creating the buffer for result.
* Will be set to "NOBITS" if no bits are set in bitvector (ie bitvector = 0). * Will be set to "NOBITS" if no bits are set in bitvector (ie bitvector = 0).
* @param[in] reslen The length of the available memory in the result buffer. * @param[in] reslen The length of the available memory in the result buffer.
* Ideally, results will be large enough to hold the description of every bit * Ideally, results will be large enough to hold the description of every bit
@ -340,14 +348,14 @@ size_t sprintbit(bitvector_t bitvector, const char *names[], char *result, size_
* responsible for creating the memory buffer for the result string. * responsible for creating the memory buffer for the result string.
* @param[in] type The type number to be translated. * @param[in] type The type number to be translated.
* @param[in] names An array of human readable strings describing each possible * @param[in] names An array of human readable strings describing each possible
* bit. The final element in this array must be a string made of a single * bit. The final element in this array must be a string made of a single
* newline character (eg "\n"). * newline character (eg "\n").
* @param[out] result Holds the translated name of the type. * @param[out] result Holds the translated name of the type.
* Caller of sprintbit is responsible for creating the buffer for result. * Caller of sprintbit is responsible for creating the buffer for result.
* Will be set to "UNDEFINED" if the type is greater than the number of names * Will be set to "UNDEFINED" if the type is greater than the number of names
* available. * available.
* @param[in] reslen The length of the available memory in the result buffer. * @param[in] reslen The length of the available memory in the result buffer.
* @retval size_t The length of the string copied into result. */ * @retval size_t The length of the string copied into result. */
size_t sprinttype(int type, const char *names[], char *result, size_t reslen) size_t sprinttype(int type, const char *names[], char *result, size_t reslen)
{ {
int nr = 0; int nr = 0;
@ -360,8 +368,8 @@ size_t sprinttype(int type, const char *names[], char *result, size_t reslen)
return strlcpy(result, *names[nr] != '\n' ? names[nr] : "UNDEFINED", reslen); return strlcpy(result, *names[nr] != '\n' ? names[nr] : "UNDEFINED", reslen);
} }
/** Take a bitarray and return a human readable description of which bits are /** Take a bitarray and return a human readable description of which bits are
* set in it. * set in it.
* @pre The final element in the names array must contain a one character * @pre The final element in the names array must contain a one character
* string consisting of a single newline character "\n". Caller of function is * string consisting of a single newline character "\n". Caller of function is
* responsible for creating the memory buffer for the result string large enough * responsible for creating the memory buffer for the result string large enough
@ -369,14 +377,14 @@ size_t sprinttype(int type, const char *names[], char *result, size_t reslen)
* possible array overflow for result. * possible array overflow for result.
* @param[in] bitvector The bitarray in which to test for set bits. * @param[in] bitvector The bitarray in which to test for set bits.
* @param[in] names An array of human readable strings describing each possible * @param[in] names An array of human readable strings describing each possible
* bit. The final element in this array must be a string made of a single * bit. The final element in this array must be a string made of a single
* newline character (eg "\n"). * newline character (eg "\n").
* If you don't have a 'const' array for the names param, cast it as such. * If you don't have a 'const' array for the names param, cast it as such.
* @param[in] maxar The number of 'bytes' in the bitarray. This number will * @param[in] maxar The number of 'bytes' in the bitarray. This number will
* usually be pre-defined for the particular bitarray you are using. * usually be pre-defined for the particular bitarray you are using.
* @param[out] result Holds the names of the set bits in bitarray. The bit * @param[out] result Holds the names of the set bits in bitarray. The bit
* names are delimited by a single space. Ideally, results will be large enough * names are delimited by a single space. Ideally, results will be large enough
* to hold the description of every bit that could possibly be set in bitvector. * to hold the description of every bit that could possibly be set in bitvector.
* Will be set to "NOBITS" if no bits are set in bitarray (ie all bits in the * Will be set to "NOBITS" if no bits are set in bitarray (ie all bits in the
* bitarray are equal to 0). * bitarray are equal to 0).
*/ */
@ -388,19 +396,19 @@ void sprintbitarray(int bitvector[], const char *names[], int maxar, char *resul
for(teller = 0; teller < maxar && !found; teller++) for(teller = 0; teller < maxar && !found; teller++)
{ {
for (nr = 0; nr < 32 && !found; nr++) for (nr = 0; nr < 32 && !found; nr++)
{ {
if (IS_SET_AR(bitvector, (teller*32)+nr)) if (IS_SET_AR(bitvector, (teller*32)+nr))
{ {
if (*names[(teller*32)+nr] != '\n') if (*names[(teller*32)+nr] != '\n')
{ {
if (*names[(teller*32)+nr] != '\0') if (*names[(teller*32)+nr] != '\0')
{ {
strcat(result, names[(teller*32)+nr]); strcat(result, names[(teller*32)+nr]);
strcat(result, " "); strcat(result, " ");
} }
} }
else else
{ {
strcat(result, "UNDEFINED "); strcat(result, "UNDEFINED ");
} }
@ -416,10 +424,10 @@ void sprintbitarray(int bitvector[], const char *names[], int maxar, char *resul
/** Calculate the REAL time passed between two time invervals. /** Calculate the REAL time passed between two time invervals.
* @todo Recommend making this function foresightedly useful by calculating * @todo Recommend making this function foresightedly useful by calculating
* real months and years, too. * real months and years, too.
* @param t2 The later time. * @param t2 The later time.
* @param t1 The earlier time. * @param t1 The earlier time.
* @retval time_info_data The real hours and days passed between t2 and t1. Only * @retval time_info_data The real hours and days passed between t2 and t1. Only
* the hours and days are returned, months and years are ignored and returned * the hours and days are returned, months and years are ignored and returned
* as -1 values. */ * as -1 values. */
struct time_info_data *real_time_passed(time_t t2, time_t t1) struct time_info_data *real_time_passed(time_t t2, time_t t1)
@ -444,7 +452,7 @@ struct time_info_data *real_time_passed(time_t t2, time_t t1)
/** Calculate the MUD time passed between two time invervals. /** Calculate the MUD time passed between two time invervals.
* @param t2 The later time. * @param t2 The later time.
* @param t1 The earlier time. * @param t1 The earlier time.
* @retval time_info_data A pointer to the mud hours, days, months and years * @retval time_info_data A pointer to the mud hours, days, months and years
* that have passed between the two time intervals. DO NOT FREE the structure * that have passed between the two time intervals. DO NOT FREE the structure
* pointed to by the return value. */ * pointed to by the return value. */
struct time_info_data *mud_time_passed(time_t t2, time_t t1) struct time_info_data *mud_time_passed(time_t t2, time_t t1)
@ -487,7 +495,7 @@ time_t mud_time_to_secs(struct time_info_data *now)
* @todo The minimum starting age of 17 is hardcoded in this function. Recommend * @todo The minimum starting age of 17 is hardcoded in this function. Recommend
* changing the minimum age to a property (variable) external to this function. * changing the minimum age to a property (variable) external to this function.
* @param ch A valid player character. * @param ch A valid player character.
* @retval time_info_data A pointer to the mud age in years of the player * @retval time_info_data A pointer to the mud age in years of the player
* character. DO NOT FREE the structure pointed to by the return value. */ * character. DO NOT FREE the structure pointed to by the return value. */
struct time_info_data *age(struct char_data *ch) struct time_info_data *age(struct char_data *ch)
{ {
@ -502,7 +510,7 @@ struct time_info_data *age(struct char_data *ch)
/** Check if making ch follow victim will create an illegal follow loop. In /** Check if making ch follow victim will create an illegal follow loop. In
* essence, this prevents someone from following a character in a group that * essence, this prevents someone from following a character in a group that
* is already being lead by the character. * is already being lead by the character.
* @param ch The character trying to follow. * @param ch The character trying to follow.
* @param victim The character being followed. * @param victim The character being followed.
* @retval bool TRUE if ch is already leading someone in victims group, FALSE * @retval bool TRUE if ch is already leading someone in victims group, FALSE
@ -519,11 +527,11 @@ bool circle_follow(struct char_data *ch, struct char_data *victim)
return (FALSE); return (FALSE);
} }
/** Call on a character (NPC or PC) to stop them from following someone and /** Call on a character (NPC or PC) to stop them from following someone and
* to break any charm affect. * to break any charm affect.
* @todo Make the messages returned from the broken charm affect more * @todo Make the messages returned from the broken charm affect more
* understandable. * understandable.
* @pre ch MUST be following someone, else core dump. * @pre ch MUST be following someone, else core dump.
* @post The charm affect (AFF_CHARM) will be removed from the character and * @post The charm affect (AFF_CHARM) will be removed from the character and
* the character will stop following the "master" they were following. * the character will stop following the "master" they were following.
* @param ch The character (NPC or PC) to stop from following. * @param ch The character (NPC or PC) to stop from following.
@ -570,7 +578,7 @@ void stop_follower(struct char_data *ch)
/** Finds the number of follows that are following, and charmed by, the /** Finds the number of follows that are following, and charmed by, the
* character (PC or NPC). * character (PC or NPC).
* @param ch The character to check for charmed followers. * @param ch The character to check for charmed followers.
* @retval int The number of followers that are also charmed by the character. * @retval int The number of followers that are also charmed by the character.
*/ */
int num_followers_charmed(struct char_data *ch) int num_followers_charmed(struct char_data *ch)
{ {
@ -586,7 +594,7 @@ int num_followers_charmed(struct char_data *ch)
/** Called when a character that follows/is followed dies. If the character /** Called when a character that follows/is followed dies. If the character
* is the leader of a group, it stops everyone in the group from following * is the leader of a group, it stops everyone in the group from following
* them. Despite the title, this function does not actually perform the kill on * them. Despite the title, this function does not actually perform the kill on
* the character passed in as the argument. * the character passed in as the argument.
* @param ch The character (NPC or PC) to stop from following. * @param ch The character (NPC or PC) to stop from following.
* */ * */
@ -606,7 +614,7 @@ void die_follower(struct char_data *ch)
/** Adds a new follower to a group. /** Adds a new follower to a group.
* @todo Maybe make circle_follow an inherent part of this function? * @todo Maybe make circle_follow an inherent part of this function?
* @pre Make sure to call circle_follow first. ch may also not already * @pre Make sure to call circle_follow first. ch may also not already
* be following anyone, otherwise core dump. * be following anyone, otherwise core dump.
* @param ch The character to follow. * @param ch The character to follow.
* @param leader The character to be followed. */ * @param leader The character to be followed. */
void add_follower(struct char_data *ch, struct char_data *leader) void add_follower(struct char_data *ch, struct char_data *leader)
@ -632,13 +640,13 @@ void add_follower(struct char_data *ch, struct char_data *leader)
act("$n starts to follow $N.", TRUE, ch, 0, leader, TO_NOTVICT); act("$n starts to follow $N.", TRUE, ch, 0, leader, TO_NOTVICT);
} }
/** Reads the next non-blank line off of the input stream. Empty lines are /** Reads the next non-blank line off of the input stream. Empty lines are
* skipped. Lines which begin with '*' are considered to be comments and are * skipped. Lines which begin with '*' are considered to be comments and are
* skipped. * skipped.
* @pre Caller must allocate memory for buf. * @pre Caller must allocate memory for buf.
* @post If a there is a line to be read, the newline character is removed from * @post If a there is a line to be read, the newline character is removed from
* the file line ending and the string is returned. Else a null string is * the file line ending and the string is returned. Else a null string is
* returned in buf. * returned in buf.
* @param[in] fl The file to be read from. * @param[in] fl The file to be read from.
* @param[out] buf The next non-blank line read from the file. Buffer given must * @param[out] buf The next non-blank line read from the file. Buffer given must
* be at least READ_SIZE (256) characters large. * be at least READ_SIZE (256) characters large.
@ -666,7 +674,7 @@ int get_line(FILE *fl, char *buf)
/** Create the full path, relative to the library path, of the player type /** Create the full path, relative to the library path, of the player type
* file to open. * file to open.
* @todo Make the return type bool. * @todo Make the return type bool.
* @pre Caller is responsible for allocating memory buffer for the created * @pre Caller is responsible for allocating memory buffer for the created
* file name. * file name.
* @post The potential file path to open is created. This function does not * @post The potential file path to open is created. This function does not
@ -741,7 +749,7 @@ int get_filename(char *filename, size_t fbufsize, int mode, const char *orig_nam
} }
/** Calculate the number of player characters (PCs) in the room. Any NPC (mob) /** Calculate the number of player characters (PCs) in the room. Any NPC (mob)
* is not returned in the count. * is not returned in the count.
* @param room The room to check for PCs. */ * @param room The room to check for PCs. */
int num_pc_in_room(struct room_data *room) int num_pc_in_room(struct room_data *room)
{ {
@ -757,12 +765,12 @@ int num_pc_in_room(struct room_data *room)
/** This function (derived from basic fork() abort() idea by Erwin S Andreasen) /** This function (derived from basic fork() abort() idea by Erwin S Andreasen)
* causes your MUD to dump core (assuming you can) but continue running. The * causes your MUD to dump core (assuming you can) but continue running. The
* core dump will allow post-mortem debugging that is less severe than assert(); * core dump will allow post-mortem debugging that is less severe than assert();
* Don't call this directly as core_dump_unix() but as simply 'core_dump()' so * Don't call this directly as core_dump_unix() but as simply 'core_dump()' so
* that it will be excluded from systems not supporting them. You still want to * that it will be excluded from systems not supporting them. You still want to
* call abort() or exit(1) for non-recoverable errors, of course. Wonder if * call abort() or exit(1) for non-recoverable errors, of course. Wonder if
* flushing streams includes sockets? * flushing streams includes sockets?
* @param who The file in which this call was made. * @param who The file in which this call was made.
* @param line The line at which this call was made. */ * @param line The line at which this call was made. */
void core_dump_real(const char *who, int line) void core_dump_real(const char *who, int line)
@ -778,7 +786,7 @@ void core_dump_real(const char *who, int line)
/* Everything, just in case, for the systems that support it. */ /* Everything, just in case, for the systems that support it. */
fflush(NULL); fflush(NULL);
/* Kill the child so the debugger or script doesn't think the MUD crashed. /* Kill the child so the debugger or script doesn't think the MUD crashed.
* The 'autorun' script would otherwise run it again. */ * The 'autorun' script would otherwise run it again. */
if (fork() == 0) if (fork() == 0)
abort(); abort();
@ -811,9 +819,9 @@ int count_color_chars(char *string)
return num; return num;
} }
/** Tests to see if a room is dark. Rules (unless overridden by ROOM_DARK): /** Tests to see if a room is dark. Rules (unless overridden by ROOM_DARK):
* Inside and City rooms are always lit. Outside rooms are dark at sunset and * Inside and City rooms are always lit. Outside rooms are dark at sunset and
* night. * night.
* @todo Make the return value a bool. * @todo Make the return value a bool.
* @param room The real room to test for. * @param room The real room to test for.
* @retval int FALSE if the room is lit, TRUE if the room is dark. */ * @retval int FALSE if the room is lit, TRUE if the room is dark. */
@ -847,21 +855,21 @@ int room_is_dark(room_rnum room)
* recommend doing an internet or wikipedia search. * recommend doing an internet or wikipedia search.
* @param s1 The input string. * @param s1 The input string.
* @param s2 The string to be compared to. * @param s2 The string to be compared to.
* @retval int The Levenshtein distance between s1 and s2. */ * @retval int The Levenshtein distance between s1 and s2. */
int levenshtein_distance(const char *s1, const char *s2) int levenshtein_distance(const char *s1, const char *s2)
{ {
int **d, i, j; int **d, i, j;
int s1_len = strlen(s1), s2_len = strlen(s2); int s1_len = strlen(s1), s2_len = strlen(s2);
CREATE(d, int *, s1_len + 1); CREATE(d, int *, s1_len + 1);
for (i = 0; i <= s1_len; i++) { for (i = 0; i <= s1_len; i++) {
CREATE(d[i], int, s2_len + 1); CREATE(d[i], int, s2_len + 1);
d[i][0] = i; d[i][0] = i;
} }
for (j = 0; j <= s2_len; j++) for (j = 0; j <= s2_len; j++)
d[0][j] = j; d[0][j] = j;
for (i = 1; i <= s1_len; i++) for (i = 1; i <= s1_len; i++)
for (j = 1; j <= s2_len; j++) for (j = 1; j <= s2_len; j++)
d[i][j] = MIN(d[i - 1][j] + 1, MIN(d[i][j - 1] + 1, d[i][j] = MIN(d[i - 1][j] + 1, MIN(d[i][j - 1] + 1,
@ -874,8 +882,8 @@ int levenshtein_distance(const char *s1, const char *s2)
free(d); free(d);
return i; return i;
} }
/** Removes a character from a piece of furniture. Unlike some of the other /** Removes a character from a piece of furniture. Unlike some of the other
* _from_ functions, this does not place the character into NOWHERE. * _from_ functions, this does not place the character into NOWHERE.
* @post ch is unattached from the furniture object. * @post ch is unattached from the furniture object.
@ -896,16 +904,16 @@ void char_from_furniture(struct char_data *ch)
NEXT_SITTING(ch) = NULL; NEXT_SITTING(ch) = NULL;
return; return;
} }
if (!(tempch = OBJ_SAT_IN_BY(furniture))){ if (!(tempch = OBJ_SAT_IN_BY(furniture))){
log("SYSERR: Char from furniture, but no furniture!"); log("SYSERR: Char from furniture, but no furniture!");
SITTING(ch) = NULL; SITTING(ch) = NULL;
NEXT_SITTING(ch) = NULL; NEXT_SITTING(ch) = NULL;
return; return;
} }
if (tempch == ch){ if (tempch == ch){
if (!NEXT_SITTING(ch)) if (!NEXT_SITTING(ch))
OBJ_SAT_IN_BY(furniture) = NULL; OBJ_SAT_IN_BY(furniture) = NULL;
else else
OBJ_SAT_IN_BY(furniture) = NEXT_SITTING(ch); OBJ_SAT_IN_BY(furniture) = NEXT_SITTING(ch);
@ -919,13 +927,13 @@ void char_from_furniture(struct char_data *ch)
if (NEXT_SITTING(tempch) != ch){ if (NEXT_SITTING(tempch) != ch){
NEXT_SITTING(tempch) = NEXT_SITTING(ch); NEXT_SITTING(tempch) = NEXT_SITTING(ch);
found++; found++;
} }
} }
if (found) if (found)
log("SYSERR: Char flagged as sitting, but not in furniture."); log("SYSERR: Char flagged as sitting, but not in furniture.");
else else
GET_OBJ_VAL(furniture, 1) -= 1; GET_OBJ_VAL(furniture, 1) -= 1;
SITTING(ch) = NULL; SITTING(ch) = NULL;
NEXT_SITTING(ch) = NULL; NEXT_SITTING(ch) = NULL;
@ -933,81 +941,81 @@ void char_from_furniture(struct char_data *ch)
} }
/* column_list /* column_list
The list is output in a fixed format, and only the number of columns can be adjusted The list is output in a fixed format, and only the number of columns can be adjusted
This function will output the list to the player This function will output the list to the player
Vars: Vars:
ch - the player ch - the player
num_cols - the desired number of columns num_cols - the desired number of columns
list - a pointer to a list of strings list - a pointer to a list of strings
list_length - So we can work with lists that don't end with /n list_length - So we can work with lists that don't end with /n
show_nums - when set to TRUE, it will show a number before the list entry. show_nums - when set to TRUE, it will show a number before the list entry.
*/ */
void column_list(struct char_data *ch, int num_cols, const char **list, int list_length, bool show_nums) void column_list(struct char_data *ch, int num_cols, const char **list, int list_length, bool show_nums)
{ {
int num_per_col, col_width,r,c,i, offset=0, len=0, temp_len, max_len=0; int num_per_col, col_width,r,c,i, offset=0, len=0, temp_len, max_len=0;
char buf[MAX_STRING_LENGTH]; char buf[MAX_STRING_LENGTH];
/* Ensure that the number of columns is in the range 1-10 */ /* Ensure that the number of columns is in the range 1-10 */
num_cols = MIN(MAX(num_cols,1), 10); num_cols = MIN(MAX(num_cols,1), 10);
/* Work out the longest list item */ /* Work out the longest list item */
for (i=0; i<list_length; i++) for (i=0; i<list_length; i++)
if (max_len < strlen(list[i])) if (max_len < strlen(list[i]))
max_len = strlen(list[i]); max_len = strlen(list[i]);
/* Calculate the width of each column */ /* Calculate the width of each column */
col_width = (GET_SCREEN_WIDTH(ch)) / num_cols; col_width = (GET_SCREEN_WIDTH(ch)) / num_cols;
if (show_nums) col_width-=4; if (show_nums) col_width-=4;
if (col_width < max_len) if (col_width < max_len)
log("Warning: columns too narrow for correct output to %s in simple_column_list (utils.c)", GET_NAME(ch)); log("Warning: columns too narrow for correct output to %s in simple_column_list (utils.c)", GET_NAME(ch));
/* Calculate how many list items there should be per column */ /* Calculate how many list items there should be per column */
num_per_col = (list_length / num_cols) + ((list_length % num_cols) ? 1 : 0); num_per_col = (list_length / num_cols) + ((list_length % num_cols) ? 1 : 0);
/* Fill 'buf' with the columnised list */ /* Fill 'buf' with the columnised list */
for (r=0; r<num_per_col; r++) for (r=0; r<num_per_col; r++)
{ {
for (c=0; c<num_cols; c++) for (c=0; c<num_cols; c++)
{ {
offset = (c*num_per_col)+r; offset = (c*num_per_col)+r;
if (offset < list_length) if (offset < list_length)
{ {
if (show_nums) if (show_nums)
temp_len = snprintf(buf+len, sizeof(buf) - len, "%2d) %-*s", offset+1, col_width, list[(offset)]); temp_len = snprintf(buf+len, sizeof(buf) - len, "%2d) %-*s", offset+1, col_width, list[(offset)]);
else else
temp_len = snprintf(buf+len, sizeof(buf) - len, "%-*s", col_width, list[(offset)]); temp_len = snprintf(buf+len, sizeof(buf) - len, "%-*s", col_width, list[(offset)]);
len += temp_len; len += temp_len;
} }
} }
temp_len = snprintf(buf+len, sizeof(buf) - len, "\r\n"); temp_len = snprintf(buf+len, sizeof(buf) - len, "\r\n");
len += temp_len; len += temp_len;
} }
if (len >= sizeof(buf)) if (len >= sizeof(buf))
snprintf((buf + MAX_STRING_LENGTH) - 22, 22, "\r\n*** OVERFLOW ***\r\n"); snprintf((buf + MAX_STRING_LENGTH) - 22, 22, "\r\n*** OVERFLOW ***\r\n");
/* Send the list to the player */ /* Send the list to the player */
page_string(ch->desc, buf, TRUE); page_string(ch->desc, buf, TRUE);
} }
/** /**
* Search through a string array of flags for a particular flag. * Search through a string array of flags for a particular flag.
* @param flag_list An array of flag name strings. The final element must * @param flag_list An array of flag name strings. The final element must
* be a string made up of a single newline. * be a string made up of a single newline.
* @param flag_name The name to search in flag_list. * @param flag_name The name to search in flag_list.
* @retval int Returns the element number in flag_list of flag_name or * @retval int Returns the element number in flag_list of flag_name or
* NOFLAG (-1) if no match. * NOFLAG (-1) if no match.
*/ */
int get_flag_by_name(const char *flag_list[], char *flag_name) int get_flag_by_name(const char *flag_list[], char *flag_name)
{ {
int i=0; int i=0;
for (;flag_list[i] && *flag_list[i] && strcmp(flag_list[i], "\n") != 0; i++) for (;flag_list[i] && *flag_list[i] && strcmp(flag_list[i], "\n") != 0; i++)
if (!strcmp(flag_list[i], flag_name)) if (!strcmp(flag_list[i], flag_name))
return (i); return (i);
return (NOFLAG); return (NOFLAG);
} }
/** /**
@ -1016,7 +1024,7 @@ int get_flag_by_name(const char *flag_list[], char *flag_name)
* @pre Expects an already open file and the user to supply enough memory * @pre Expects an already open file and the user to supply enough memory
* in the output buffer to hold the lines read from the file. Assumes the * in the output buffer to hold the lines read from the file. Assumes the
* file is a text file. Expects buf to be nulled out if the entire buf is * file is a text file. Expects buf to be nulled out if the entire buf is
* to be used, otherwise, appends file information beyond the first null * to be used, otherwise, appends file information beyond the first null
* character. lines_to_read is assumed to be a positive number. * character. lines_to_read is assumed to be a positive number.
* @post Rewinds the file pointer to the beginning of the file. If buf is * @post Rewinds the file pointer to the beginning of the file. If buf is
* too small to handle the requested output, **OVERFLOW** is appended to the * too small to handle the requested output, **OVERFLOW** is appended to the
@ -1047,14 +1055,14 @@ int file_head( FILE *file, char *buf, size_t bufsize, int lines_to_read )
{ {
return lines_to_read; return lines_to_read;
} }
/* Initialize local variables not already initialized. */ /* Initialize local variables not already initialized. */
buflen = strlen(buf); buflen = strlen(buf);
/* Read from the front of the file. */ /* Read from the front of the file. */
rewind(file); rewind(file);
while ( (lines_read < lines_to_read) && while ( (lines_read < lines_to_read) &&
(readstatus > 0) && (buflen < bufsize) ) (readstatus > 0) && (buflen < bufsize) )
{ {
/* Don't use get_line to set lines_read because get_line will return /* Don't use get_line to set lines_read because get_line will return
@ -1068,7 +1076,7 @@ int file_head( FILE *file, char *buf, size_t bufsize, int lines_to_read )
lines_read++; lines_read++;
} }
} }
/* Check to see if we had a potential buffer overflow. */ /* Check to see if we had a potential buffer overflow. */
if (buflen >= bufsize) if (buflen >= bufsize)
{ {
@ -1076,17 +1084,17 @@ int file_head( FILE *file, char *buf, size_t bufsize, int lines_to_read )
if ( (strlen(overflow) + 1) >= bufsize ) if ( (strlen(overflow) + 1) >= bufsize )
{ {
core_dump(); core_dump();
snprintf( buf, bufsize, "%s", overflow); snprintf( buf, bufsize, "%s", overflow);
} }
else else
{ {
/* Append the overflow statement to the buffer. */ /* Append the overflow statement to the buffer. */
snprintf( buf + buflen - strlen(overflow) - 1, strlen(overflow) + 1, "%s", overflow); snprintf( buf + buflen - strlen(overflow) - 1, strlen(overflow) + 1, "%s", overflow);
} }
} }
rewind(file); rewind(file);
/* Return the number of lines. */ /* Return the number of lines. */
return lines_read; return lines_read;
} }
@ -1097,7 +1105,7 @@ int file_head( FILE *file, char *buf, size_t bufsize, int lines_to_read )
* @pre Expects an already open file and the user to supply enough memory * @pre Expects an already open file and the user to supply enough memory
* in the output buffer to hold the lines read from the file. Assumes the * in the output buffer to hold the lines read from the file. Assumes the
* file is a text file. Expects buf to be nulled out if the entire buf is * file is a text file. Expects buf to be nulled out if the entire buf is
* to be used, otherwise, appends file information beyond the first null * to be used, otherwise, appends file information beyond the first null
* character in buf. lines_to_read is assumed to be a positive number. * character in buf. lines_to_read is assumed to be a positive number.
* @post Rewinds the file pointer to the beginning of the file. If buf is * @post Rewinds the file pointer to the beginning of the file. If buf is
* too small to handle the requested output, **OVERFLOW** is appended to the * too small to handle the requested output, **OVERFLOW** is appended to the
@ -1124,33 +1132,33 @@ int file_tail( FILE *file, char *buf, size_t bufsize, int lines_to_read )
int readstatus = 1; /* Are we at the end of the file? */ int readstatus = 1; /* Are we at the end of the file? */
int n = 0; /* Return value from snprintf. */ int n = 0; /* Return value from snprintf. */
const char *overflow = "\r\n**OVERFLOW**\r\n"; /* Appended if overflow. */ const char *overflow = "\r\n**OVERFLOW**\r\n"; /* Appended if overflow. */
/* Quick check for bad arguments. */ /* Quick check for bad arguments. */
if (lines_to_read <= 0) if (lines_to_read <= 0)
{ {
return lines_to_read; return lines_to_read;
} }
/* Initialize local variables not already initialized. */ /* Initialize local variables not already initialized. */
buflen = strlen(buf); buflen = strlen(buf);
total_lines = file_numlines(file); /* Side effect: file is rewound. */ total_lines = file_numlines(file); /* Side effect: file is rewound. */
/* Fast forward to the location we should start reading from */ /* Fast forward to the location we should start reading from */
while (((lines_to_read + lines_read) < total_lines)) while (((lines_to_read + lines_read) < total_lines))
{ {
do { do {
c = fgetc(file); c = fgetc(file);
} while(c != '\n'); } while(c != '\n');
lines_read++; lines_read++;
} }
/* We reuse the lines_read counter. */ /* We reuse the lines_read counter. */
lines_read = 0; lines_read = 0;
/** From here on, we perform just like file_head */ /** From here on, we perform just like file_head */
while ( (lines_read < lines_to_read) && while ( (lines_read < lines_to_read) &&
(readstatus > 0) && (buflen < bufsize) ) (readstatus > 0) && (buflen < bufsize) )
{ {
/* Don't use get_line to set lines_read because get_line will return /* Don't use get_line to set lines_read because get_line will return
* the number of comments skipped during reading. */ * the number of comments skipped during reading. */
@ -1163,7 +1171,7 @@ int file_tail( FILE *file, char *buf, size_t bufsize, int lines_to_read )
lines_read++; lines_read++;
} }
} }
/* Check to see if we had a potential buffer overflow. */ /* Check to see if we had a potential buffer overflow. */
if (buflen >= bufsize) if (buflen >= bufsize)
{ {
@ -1171,20 +1179,20 @@ int file_tail( FILE *file, char *buf, size_t bufsize, int lines_to_read )
if ( (strlen(overflow) + 1) >= bufsize ) if ( (strlen(overflow) + 1) >= bufsize )
{ {
core_dump(); core_dump();
snprintf( buf, bufsize, "%s", overflow); snprintf( buf, bufsize, "%s", overflow);
} }
else else
{ {
/* Append the overflow statement to the buffer. */ /* Append the overflow statement to the buffer. */
snprintf( buf + buflen - strlen(overflow) - 1, strlen(overflow) + 1, "%s", overflow); snprintf( buf + buflen - strlen(overflow) - 1, strlen(overflow) + 1, "%s", overflow);
} }
} }
rewind(file); rewind(file);
/* Return the number of lines read. */ /* Return the number of lines read. */
return lines_read; return lines_read;
} }
/** Returns the byte size of a file. We assume size_t to be a large enough type /** Returns the byte size of a file. We assume size_t to be a large enough type
@ -1193,13 +1201,13 @@ int file_tail( FILE *file, char *buf, size_t bufsize, int lines_to_read )
* @pre file parameter must already be opened. * @pre file parameter must already be opened.
* @post file will be rewound. * @post file will be rewound.
* @param file The file to determine the size of. * @param file The file to determine the size of.
* @retval size_t The byte size of the file (we assume no errors will be * @retval size_t The byte size of the file (we assume no errors will be
* encountered in this function). * encountered in this function).
*/ */
size_t file_sizeof( FILE *file ) size_t file_sizeof( FILE *file )
{ {
size_t numbytes = 0; size_t numbytes = 0;
rewind(file); rewind(file);
/* It would be so much easier to do a byte count if an fseek SEEK_END and /* It would be so much easier to do a byte count if an fseek SEEK_END and
@ -1210,11 +1218,11 @@ size_t file_sizeof( FILE *file )
while (!feof(file)) while (!feof(file))
{ {
fgetc(file); fgetc(file);
numbytes++; numbytes++;
} }
rewind(file); rewind(file);
return numbytes; return numbytes;
} }
@ -1224,14 +1232,14 @@ size_t file_sizeof( FILE *file )
* @pre file parameter must already be opened. * @pre file parameter must already be opened.
* @post file will be rewound. * @post file will be rewound.
* @param file The file to determine the size of. * @param file The file to determine the size of.
* @retval size_t The byte size of the file (we assume no errors will be * @retval size_t The byte size of the file (we assume no errors will be
* encountered in this function). * encountered in this function).
*/ */
int file_numlines( FILE *file ) int file_numlines( FILE *file )
{ {
int numlines = 0; int numlines = 0;
char c; char c;
rewind(file); rewind(file);
while (!feof(file)) while (!feof(file))
@ -1242,9 +1250,9 @@ int file_numlines( FILE *file )
numlines++; numlines++;
} }
} }
rewind(file); rewind(file);
return numlines; return numlines;
} }
@ -1254,17 +1262,17 @@ int file_numlines( FILE *file )
* @pre Assumes that NOWHERE, NOTHING, NOBODY, NOFLAG, etc are all equal. * @pre Assumes that NOWHERE, NOTHING, NOBODY, NOFLAG, etc are all equal.
* @param str_to_conv A string of characters to attempt to convert to an * @param str_to_conv A string of characters to attempt to convert to an
* IDXTYPE number. * IDXTYPE number.
* @retval IDXTYPE A valid index number, or NOWHERE if not valid. * @retval IDXTYPE A valid index number, or NOWHERE if not valid.
*/ */
IDXTYPE atoidx( const char *str_to_conv ) IDXTYPE atoidx( const char *str_to_conv )
{ {
long int result; long int result;
/* Check for errors */ /* Check for errors */
errno = 0; errno = 0;
result = strtol(str_to_conv, NULL, 10); result = strtol(str_to_conv, NULL, 10);
if ( errno || (result > IDXTYPE_MAX) || (result < 0) ) if ( errno || (result > IDXTYPE_MAX) || (result < 0) )
return NOWHERE; /* All of the NO* settings should be the same */ return NOWHERE; /* All of the NO* settings should be the same */
else else