17.1 The master object
Pike is a very dynamic language. Sometimes that is not enough, sometimes you
want to change the way Pike handles errors, loads modules or start scripts.
All this and much more can be changed by modifying the master object.
The master object is a Pike object like any other object, but it is
loaded before anything else and is expected to perform certain things for
the Pike executable. The Pike executable cannot function without a master
object to take care of these things. Here is a list of the methods needed
in the master object:
- program cast_to_program(string program_name, string current_file)
- This function is called whenever someone performs a cast from a string
to a program.
- program handle_inherit(string program_name, string current_file)
- This is called whenever a Pike program which uses inherit with a string
argument is called. It is expected to return the program to inherit.
- void handle_error(array trace)
- This function is expected to write the error messages when a
run time error occurs. The argument is of the form
({"error_description", backtrace() }). If any error
occurs in this routine Pike will dump core.
- program cast_to_program(string program_name, string current_file)
- This function is called whenever someone performs a cast from a string
to an object.
- mixed resolv(string identifier, string current_file)
- This function is called whenever the compiler finds an unknown identifier
in a program. It is normally used for loading modules.
It is supposed to return ([])[0] if the master doesn't know what
the value should be, and the value in question otherwise.
- void _main(array(string) argv, array(string) env)
- This function is supposed to start a Pike script. It receives all
the command line arguments in the first array and all environment
variables on the form "var=value".
_main is called as soon as all modules and setup is done.
- void compile_error(string file, int line, string err)
- This function is called whenever a compile error is encountered. Normally
it just writes a message to stderr.
- string handle_include(string file, string current_file, int local_include)
- This function is used to locate include files. file is the file
name the user wants to include, and local_include is 1 if
the user used double quotes rather than lesser-than, greater-than to
quote the file name. Otherwise it is zero.
Aside from the above functions, which are expected from the Pike binary,
the master object is also expected to provide functions used by Pike
scripts. The current master object adds the following global functions:
-
add_include_path,
remove_include_path,
add_module_path,
remove_module_path,
add_program_path,
remove_program_path,
master,
describe_backtrace,
mkmultiset,
strlen,
new,
clone,
UNDEFINED,
write,
getenv and putenv.
There are at least two ways to change the behavior of the master object.
(Except for editing it directly, which would cause other Pike scripts not
to run in most cases.) You can either copy the master object, modify it
and use the command line option -m to load your file instead of
the default master object. However, since there might be more functionality
added to the master object in the future I do not recommend this.
A better way is to write an object that inherits the master and then calls
replace_master with the new object as argument. This should be far more
future-safe. Although I can not guarantee that the interface between Pike
and the master object will not change in the future, so be careful if you
do this.
Let's look an example:
#!/usr/local/bin/pike
class new_master {
inherit "/master";
void create()
{
/* You need to copy the values from the old master to the new */
/* NOTE: At this point we are still using the old master */
object old_master = master();
object new_master = this_object();
foreach(indices(old_master), string varname)
{
/* The catch is needed since we can't assign constants */
catch { new_master[varname] = old_master[varname]; };
}
}
void handle_error(array trace)
{
Stdio.write_file("error log",describe_backtrace(trace));
}
};
int main(int argc, array(string) argv)
{
replace_master(new_master());
/* Run rest of program */
exit(0);
}
This example installs a master object which logs run time errors to file
instead of writing them to stderr.