diff options
-rw-r--r-- | Changelog-Trunk.txt | 1 | ||||
-rw-r--r-- | conf/script_athena.conf | 6 | ||||
-rw-r--r-- | src/map/script.c | 97 | ||||
-rw-r--r-- | src/map/script.h | 1 |
4 files changed, 105 insertions, 0 deletions
diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index 51523562d..56e201b7b 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -1,6 +1,7 @@ Date Added 2010/12/11 + * Added support for checking argument data type of built-in script functions (bugreport:1701, topic:261833, related r14573). [Ai4rei] * Fixed error message in intif_parse_mercenary_received printing wrong struct size (bugreport:4633, since r13116). [Ai4rei] 2010/12/10 * Replaced buildin_getpartyname_sub, buildin_getguildname_sub and buildin_getguildmaster_sub, which create only unnecessary overhead, with equivalent inlined code. [Ai4rei] diff --git a/conf/script_athena.conf b/conf/script_athena.conf index f45af4bad..8264c0efe 100644 --- a/conf/script_athena.conf +++ b/conf/script_athena.conf @@ -32,4 +32,10 @@ check_gotocount: 2048 //input_max_value: 2147483647 input_max_value: 10000000 +// Specifies whether or not each built-in function's arguments are checked for +// correct type. When a function is given an argument different from what it +// expects, a warning is thrown before the function is ran anyway. +// Default: yes +warn_func_mismatch_argtypes: yes + import: conf/import/script_conf.txt diff --git a/src/map/script.c b/src/map/script.c index e50867905..f1f73bbb7 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -210,6 +210,7 @@ DBMap* script_get_userfunc_db(){ return userfunc_db; } static DBMap* autobonus_db=NULL; // char* script -> char* bytecode struct Script_Config script_config = { + 1, // warn_func_mismatch_argtypes 1, 65535, 2048, //warn_func_mismatch_paramnum/check_cmdcount/check_gotocount 0, INT_MAX, // input_min_value/input_max_value "OnPCDieEvent", //die_event_name @@ -2981,6 +2982,94 @@ void op_1(struct script_state* st, int op) } +/// Checks the type of all arguments passed to a built-in function. +/// +/// @param st Script state whose stack arguments should be inspected. +/// @param func Built-in function for which the arguments are intended. +static void script_check_buildin_argtype(struct script_state* st, int func) +{ + char type; + int idx, invalid = 0; + script_function* sf = &buildin_func[str_data[func].val]; + + for( idx = 2; script_hasdata(st, idx); idx++ ) + { + struct script_data* data = script_getdata(st, idx); + + type = sf->arg[idx-2]; + + if( type == '?' || type == '*' ) + {// optional argument or unknown number of optional parameters ( no types are after this ) + break; + } + else if( type == 0 ) + {// more arguments than necessary ( should not happen, as it is checked before ) + ShowWarning("Found more arguments than necessary.\n"); + invalid++; + break; + } + else + { + const char* name = NULL; + + if( data_isreference(data) ) + {// get name for variables to determine the type they refer to + name = reference_getname(data); + } + + switch( type ) + { + case 'v': + if( !data_isstring(data) && !data_isint(data) && !data_isreference(data) ) + {// variant + ShowWarning("Unexpected type for argument %d. Expected string, number or variable.\n", idx-1); + script_reportdata(data); + invalid++; + } + break; + case 's': + if( !data_isstring(data) && !( data_isreference(data) && is_string_variable(name) ) ) + {// string + ShowWarning("Unexpected type for argument %d. Expected string.\n", idx-1); + script_reportdata(data); + invalid++; + } + break; + case 'i': + if( !data_isint(data) && !( data_isreference(data) && ( reference_toparam(data) || reference_toconstant(data) || !is_string_variable(name) ) ) ) + {// int ( params and constants are always int ) + ShowWarning("Unexpected type for argument %d. Expected number.\n", idx-1); + script_reportdata(data); + invalid++; + } + break; + case 'r': + if( !data_isreference(data) ) + {// variables + ShowWarning("Unexpected type for argument %d. Expected variable.\n", idx-1); + script_reportdata(data); + invalid++; + } + break; + case 'l': + if( !data_islabel(data) && !data_isfunclabel(data) ) + {// label + ShowWarning("Unexpected type for argument %d. Expected label.\n", idx-1); + script_reportdata(data); + invalid++; + } + break; + } + } + } + + if(invalid) + { + ShowDebug("Function: %s\n", get_str(func)); + script_reportsrc(st); + } +} + /// Executes a buildin command. /// Stack: C_NAME(<command>) C_ARG <arg0> <arg1> ... <argN> @@ -3016,6 +3105,11 @@ int run_func(struct script_state *st) return 1; } + if( script_config.warn_func_mismatch_argtypes ) + { + script_check_buildin_argtype(st, func); + } + if(str_data[func].func){ if (str_data[func].func(st)) //Report error script_reportsrc(st); @@ -3383,6 +3477,9 @@ int script_config_read(char *cfgName) else if(strcmpi(w1,"input_max_value")==0) { script_config.input_max_value = config_switch(w2); } + else if(strcmpi(w1,"warn_func_mismatch_argtypes")==0) { + script_config.warn_func_mismatch_argtypes = config_switch(w2); + } else if(strcmpi(w1,"import")==0){ script_config_read(w2); } diff --git a/src/map/script.h b/src/map/script.h index 8e9acabaf..9bc697e98 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -11,6 +11,7 @@ extern int potion_hp, potion_per_hp, potion_sp, potion_per_sp; extern int potion_target; extern struct Script_Config { + unsigned warn_func_mismatch_argtypes : 1; unsigned warn_func_mismatch_paramnum : 1; int check_cmdcount; int check_gotocount; |