Notes on functions

Navigation

Site

I'm a little terse and assume you kinda know what you're doing and have skimmed the Guide For Gods.

Much of this is also relevant to new commands, and to other hacking of the code. I'll rename the page one of these days, and give most of this information to Javelin to put in the Guide.

Where to put new functions

Preferrably, in src/funlocal.c, as any changes you make there are far less likely to break future patches. However, anything that must access the descriptors of connected players must go in src/bsd.c. You can also add the functions to the function table from there without messing with src/function.c. See the comments in the file.

Arguments and returning values

Softcode Function implementation functions take a lot of arguments. For that, and so various tools used in building the mush can recognize them, use FUNCTION to define the function. See the source for the many examples, as well as the Guide For Gods.

The arguments passed to the function when it's called in softcode are in the args array, and the number of arguments is in nargs. The length of each corresponding element of args is in arglens (arglens[0] == strlen(args[0])). buff and bp are used to return a value from the function, using the safe_XXX functions described below. All these arguments are strings. There's others, the dbrefs of the executor, enactor, and such.

Datatypes

There are 6 main data types in softcode: Booleans, which are true/false values. Integers, which are whole numbers. Unsigned integers, which are integers that can't have a value less than 0. Numbers, which are floating-point numbers. Integers can be used in place of Numbers, but not the other way around. Dbrefs, like #1234, and strings - everything else. Since all arguments are passed to functions as strings, and they return strings, there are routines available for converting between string and native format and back.

For each datatype, there are a pair of functions to convert a string to the C type, and the C type to a string (Stored in a static buffer, so it will be overwritten by the next call to the conversion function). There are no conversions for strings, since they're not needed, because strings are strings. There are also functions for appending a datatype onto the function's return buff. They all take three arguments - the data, buff, and bp. There is also a predicate function, which returns a true value if the string argument represents the given data type.

Datatype Predicate String -> C C ->String safe_XXX()
Boolean (C int) is_boolean() parse_boolean() unparse_boolean() safe_boolean()
Integer (C int) is_integer() parse_integer() unparse_integer() safe_integer()
Unsigned Integer (C unsigned int) is_uinteger() parse_uinteger() unparse_uinteger() None
Number (C NVAL [really double]) is_number() parse_number() unparse_number() safe_number()
Dbref (C dbref) is_dbref() parse_dbref() unparse_dbref() safe_dbref()
String (C char *) None None None safe_str()/safe_strl()
  • This table and notes are current for 1.7.5p5
  • Single characters can be placed on the output buffer with safe_chr(chr, buff, bp). This is a macro, so no side-effects should be in its arguments!
  • For datatypes without a safe_XXX() function, safe_str(unparse_XXX(), buff, bp) can be used.
  • There's also a safe_format(buff, bp, "printf-style format", ...) function to replace use of safe_str(tprintf(format, ...), buff, bp).
  • safe_strl(const char *str, size_t n, buff, bp) will append n characters from str to buff. str must be n or more characters long.

Lists

A lot of functions take at least one argument that's a list with a arbitrary seperator, usually with a default of space. Here's some functions to make manipulating those lists easier.

int delim_check(char *buff, char **bp, int nargs, char *args[], int seperator_position, int *seperator_var)
This function will check for the presence of an optional delimiter argument to the softcode function (Based on the position given in the seperator_position argument, with the first argument 1, the second 2, and so on), and if it's valid, set seperator_var to the right value, and return 1. If the argument isn't given, the variable is set to space, and it still returns 1. If it's an invalid argument - like one that's not just one character, an error message will be appended to buff, and it will return 0. It's commonly used as follows:
     if (!delim_check(buff, bp, nargs, args, 3, &some_char_variable))
        return;
int list2arr(char *array[], int max_size, char *list, char sep)
This function will break list up into sep-delimited chunks, placing the first max_size entries into array, which must be big enough to hold max_size character pointers. list is destructively modified. array's elements end up pointing into it, so the variables share the same memory. It returns the number of items stored in array.
char *trim_space_sep(char *str, char sep)
If sep is a space, this function trims trailing spaces from str, and returns a pointer to the first non-space character in str. Otherwise it returns str.
char *split_token(char **sp, char sep)
This function advances *sp to the next occurance of sep, sets it to nul, and returns a pointer to the start of *sp. Basically, it returns the next item from the list, and advances the list beyond that item. It returns NULL when the list is empty.

Raevnos

Last modified: Sun Jun 2 10:51:13 PDT 2002

Valid XHTML 1.0! Valid CSS!