/**
* This handler keeps track of global defines that have been
* defined as strings, and can be used to resolve them if needed.
* Its main use is to make string_to_define() simul_efun a few
* thousand times faster, amongst other things.
* @author Sandoz
*/
#define RESOLVER "/tmp/def_tmp"
#include <runtime_config.h>
private mapping global_defs;
private string gif, *ids;
private void rehash_defines();
private void destruct_resolver();
private void create() {
rehash_defines();
} /* create() */
private void rehash_defines() {
int i;
string tmp, dir, name;
string *include_list, *define_list, *processed;
global_defs = ([ ]);
if( !sizeof(ids) ) {
if( !( tmp = get_config( __INCLUDE_DIRS__ ) ) ||
!( i = sizeof( ids = explode( tmp, ":") - ({ 0, ""}) ) ) )
error("Oh no! We don't have any include dirs!\n");
while( i-- )
if( ids[i][<1] != '/' )
ids[i] += "/";
}
if( !gif || !file_exists(gif) ) {
if( !( tmp = get_config( __GLOBAL_INCLUDE_FILE__ ) ) ||
tmp[0] != '<' || tmp[<1] != '>')
error("Oh no! We don't have a global include file!\n");
tmp = tmp[1..<2];
foreach( dir in ids ) {
if( file_exists( dir + tmp ) ) {
gif = dir + tmp;
break;
}
}
if( !gif )
error("Oh no! We don't have a global include file!\n");
}
include_list = ({ gif });
define_list = processed = ({ });
while( sizeof( include_list ) ) {
processed += ({ dir = include_list[0] });
include_list = include_list[1..];
tmp = unguarded( (: read_file, dir :) );
foreach( tmp in explode( tmp, "\n") - ({ 0, ""}) ) {
if( sscanf( tmp, "#define %*s(%*s)%*s") == 3 ||
sscanf( tmp, "#define %*s %*s()") == 2 )
continue;
if( sscanf( tmp, "#define %s %*s", name ) == 2 &&
upper_case(name) == name ) {
define_list += ({ name });
continue;
}
if( sscanf( tmp, "#include <%s>%*s", name ) ) {
foreach( dir in ids ) {
if( file_exists( dir + name ) &&
member_array( dir + name, processed ) == -1 &&
member_array( dir + name, include_list ) == -1 ) {
include_list += ({ dir + name });
break;
}
}
}
}
}
global_defs = allocate_mapping( sizeof(define_list) );
define_list = map( define_list,
(: sprintf("#ifdef %s\n ob->add_define(\"%s\", %s );\n#endif",
$1, $1, $1 ) :) );
tmp = "void create() {\n"
" object ob = find_object(\""+file_name(TO)+"\");\n\n"+
implode( define_list, "\n")+"\n\n"
" destruct(TO);\n\n}\n";
unguarded( (: write_file, RESOLVER+".c", tmp, 1 :) );
call_out( (: destruct_resolver :), 1 );
catch( load_object(RESOLVER) );
} /* rehash_defines() */
/** @ignore yes */
private void destruct_resolver() {
object ob;
if( ob = find_object(RESOLVER) )
destruct(ob);
if( file_exists(RESOLVER+".c") )
unguarded( (: rm, RESOLVER+".c" :) );
} /* destruct_resolver() */
/** @ignore yes */
int force_update_defines() {
if( !adminp( previous_object(-1) ) )
return 0;
write("Rehashing defines...");
rehash_defines();
write("Rehash completed...");
return 1;
} /* force_update_defines() */
/** @ignore yes */
void add_define( string name, string value ) {
if( member_array( TO, previous_object(-1) ) != -1 &&
stringp(value) )
global_defs[name] = value;
} /* add_define() */
/**
* This method returns the mapping of all global defines.
* @return the mapping of global defines
*/
mapping query_global_defines() { return copy(global_defs); }
/**
* This method resolves a global define.
* @param str the string to resolve
* @return the resolved value, or 0
*/
string string_to_define( string str ) { return global_defs[str]; }
/** @ignore yes */
mixed stats() { return ({ ({ "global defines", sizeof(global_defs) }) }); }