There are a number of different ways to go about this. Just be warned, both of these solutions require you to edit CI's core files. That means you can't upgrade without breaking these edits. Unfortunately hooks do not suitably address this issue.
The easy way:
line 188-195 in system/vodeigniter/CodeIgniter.php handle the logic for what happens when a controller is not found.
The harder but better way:
There is a hook (http://codeigniter.com/user_guide/general/hooks.html)
pre_controller
But this will not work! The reason is that this is called after the controller has been determined, but before anything is actually executed. In other words, it is too late. The next earlier one
pre_system
is in fact too early, because routing has not been done and anything you do the routing will get overwritten.
So I needed the first controller to look the same, yet end up calling a different controller. The reason was that the page was accessed in a hierarchical way, so that it would be the subsection of a subsection and so on.
What I did was add on line 43 of system/libraries/Controller.php
$this->_ci_initialize();
Basically I had it autoload the libraries BEFORE the controller was called, because I was finding that the libraries were not loaded before the controller was called and I needed it to be done so because I needed to check user access authentication and hook directly into the routing itself.
After I did that, I extended one of the native core libraries that were autoloaded (in this case session, for applicaiton specific reasons) and then executed the rerouting.
$RTR = & load_class( 'Router' );
$this->URI = & load_class( 'URI' );
$this->URI->_fetch_uri_string();
I called this code in the start, then put my logic afterwards. This is a sample of what my rerouting logic looks like
if ( $this->segment( 1 ) == 'institute' )
{
if ( ! in_array( $this->segment( 3 ), $course ) )
{
$RTR->set_class( 'courseClass' );
$RTR->set_method( 'index' );
if ( ! $this->segment( 4 ) )
{
$RTR->set_class( 'course' );
$RTR->set_method( 'index' );
}
else
{
$RTR->set_class( 'course' );
$RTR->set_method( $this->segment( 3 ) );
}
}
The original is much longer. I probably should consider writing some sort of plugin or superior way to handle the rewriting rather than silly spagetti logic. However, I needed extremely fine grain control of the controllers being called based on the URLs. This will literally give you god mode control over your controller based on the URLs. Is it a hack? Yes. Is it inelegant? Absolutely. But I needed it done.
Just remember since this edits the core files, you can't easily upgrade after. I think the Kohana framework has a solution to this.