Short: New efuns function_file() and function_line() From: Andre Meiske Date: 2001-09-28 Type: Patch State: New - implemented in 3.3.110 We've got two new efuns for inclusion into the driver: - function_file Much like function_exists, but in the case where the actual code file is #include'd (bad style, I know..), the name of the included file is appended in brackets. - function_line Returns the line number where the function code starts in abovesaid file. Those two functions make it easy to write a (much needed) tool to look up the actual code of a function in question :) You know - the best documentation ends in '.c', and we like to have direct access to this 'documentation' from inside the MUD. It's me again. We discovered that our last patch didn't quite yield the results we wanted, for function_exists (and therefore the two new efuns function_line and function_file we wrote) didn't show private or static functions. As this is not entirely what we need, we added another parameter to abovementioned efuns which (when set) shows thus hidden functions as well. Problem is: We had to change the implementation to 'varargs' (using NUM_ARGS and stuff). Hopefully our changes will NOT break the stack, as we compared our code with other 'varargs'-efuns, but please take a look. diff -ur -x *.orig src.orig/func_spec src/func_spec --- src.orig/func_spec Mon Sep 24 11:22:57 2001 +++ src/func_spec Tue Sep 25 15:05:25 2001 @@ -258,7 +258,9 @@ void destruct(object); int exec(object, object); object find_object(string); -string function_exists(string, object default: F_THIS_OBJECT); +string function_exists(string, ...); +int function_line(string, ...); +string function_file(string, ...); int input_to(string, void|int, ...); int interactive(object default: F_THIS_OBJECT); string load_name(int|string|object default: F_THIS_OBJECT); diff -ur -x *.orig src.orig/interpret.c src/interpret.c --- src.orig/interpret.c Mon Sep 24 11:18:58 2001 +++ src/interpret.c Tue Sep 25 15:26:25 2001 @@ -14992,6 +14992,8 @@ break; } + CASE(F_FUNCTION_LINE); + CASE(F_FUNCTION_FILE); CASE(F_FUNCTION_EXISTS); /* --- function_exists --- */ { /* EXEC function_exists() @@ -15004,16 +15006,61 @@ * object. In native mode, the returned name always begins with a * '/' (absolute path). 0 is returned if the function was not * defined, or was defined as static. + * + * EXEC function_line() + * + * int function_line(string str, object ob) + * + * Returns the line number where the code of the given function + * starts in the program file, more precisely the position of the + * opening brace. + * + * EXEC function_file() + * + * string function_file(string str, object ob) + * + * Returns the file name of the source code file which defines + * functions str in object ob. Countrary to function_exists() this + * function backtracks into included files and add their file name + * in brackets after the name of the file which does the include. + * */ - char *str, *res, *p; + char *str, *res, *p, *str2; + uint32 lineno; + svalue_t *arg; + object_t *ob; + p_int show_hidden; + + GET_NUM_ARG + inter_pc = pc; + inter_sp = sp; + arg = sp- num_arg + 1; - TYPE_TEST1(sp-1, T_STRING) - TYPE_TEST2(sp, T_OBJECT) - inter_sp = sp; /* error possible when out of memory */ - str = function_exists((sp-1)->u.string, sp->u.ob); - free_svalue(sp); - free_svalue(--sp); + ob = current_object; + show_hidden = 0; + + TYPE_TEST1(arg, T_STRING) + + if (num_arg > 1) + { + if (arg[1].type == T_OBJECT) + ob = arg[1].u.ob; + else + goto bad_arg_2; + } + + if (num_arg > 2) + { + if (arg[2].type == T_NUMBER) + show_hidden = arg[2].u.number; + else + goto bad_arg_3; + } + + str = function_exists((arg)->u.string, ob, show_hidden, &str2, &lineno); + pop_n_elems(num_arg); + if (str) { /* Make a copy of the string so that we can remove @@ -15035,14 +15082,34 @@ if (!res) { - sp--; ERROR("Out of memory\n") } - put_malloced_string(sp, res); + switch(instruction) + { + case F_FUNCTION_LINE: + push_number(lineno); + break; + case F_FUNCTION_FILE: + if(str2) + { + if (compat_mode) + res = string_copy (str2); + else + res = add_slash(str2); + push_malloced_string(res); + } else { + push_number(0); + } + break; + default: + case F_FUNCTION_EXISTS: + push_malloced_string(res); + break; + } } else { - put_number(sp, 0); + push_number(0); } break; } @@ -21098,13 +21165,13 @@ /*-------------------------------------------------------------------------*/ char * -function_exists (char *fun, object_t *ob) +function_exists (char *fun, object_t *ob, p_int show_hidden, char **prog_name, uint32 *prog_line) /* Search for the function <fun> in the object <ob>. If existing, return * the name of the program, if not return NULL. * * Visibility rules apply: static and protected functions can't be - * found from the outside. + * found from the outside except when show_hidden is set. */ { @@ -21137,8 +21204,8 @@ /* Is it visible for the caller? */ flags = progp->functions[ix]; - if (flags & TYPE_MOD_PRIVATE - || (flags & TYPE_MOD_STATIC && current_object != ob)) + if (!show_hidden && (flags & TYPE_MOD_PRIVATE + || (flags & TYPE_MOD_STATIC && current_object != ob))) return NULL; /* Resolve inheritance */ @@ -21162,6 +21229,8 @@ } /* We got it. */ + + *prog_line = get_line_number(funstart,progp,prog_name); return progp->name; } /* function_exists() */ diff -ur -x *.orig src.orig/interpret.h src/interpret.h --- src.orig/interpret.h Mon Sep 24 11:39:56 2001 +++ src/interpret.h Tue Sep 25 15:28:05 2001 @@ -151,7 +151,7 @@ extern svalue_t *sapply_int(char *fun, object_t *ob, int num_arg, Bool b_ign_prot); #define sapply(f,o,n) sapply_int(f,o,n, MY_FALSE) extern svalue_t *apply(char *fun, object_t *ob, int num_arg); -extern char *function_exists(char *fun, object_t *ob); +extern char *function_exists(char *fun, object_t *ob, p_int show_hidden, char **prog_name, uint32 *prog_line); extern void call_function(program_t *progp, int fx); extern int get_line_number(bytecode_p p, program_t *progp, char **namep); extern char *collect_trace(strbuf_t * sbuf, vector_t ** rvec);