ToolResult ToolMain( OptionSet& options, istream& in, ostream& out )
{
  ToolResult result = noError;
  string transmissionList = options.getopt( "-t|-T|--transmit", "spd" );
  bool transmitStates = ( transmissionList.find_first_of( "sS" ) != string::npos ),
       transmitParameters = ( transmissionList.find_first_of( "pP" ) != string::npos ),
       transmitData = ( transmissionList.find_first_of( "dD" ) != string::npos ),
       calibrateData = !options.findopt( "-r|-R|--raw" );
  string paramFileName = options.getopt( "-p|-P|--parameters", "" );
  string offsetString = options.getopt( "-s|-S|--start", "" );
  string durationString = options.getopt( "-d|-D|--duration", "" );

  // Read the BCI2000 header.
  string token;
  int headerLength,
      sourceCh,
      stateVectorLength;
  SignalType dataFormat;
  StateList states;
  enum { v10, v11 } fileFormatVersion = v10;

  bool legalInput = in >> token;
  if( legalInput && token == "BCI2000V=" )
  {
    legalInput = legalInput &&
      in >> token;
    if( token == "1.1" )
      fileFormatVersion = v11;
    else
      legalInput = false;
    legalInput = legalInput &&
      in >> token;
  }
int main( int argc, char** argv )
{
  if( ToolInfo[ name ] == "" )
  {
    size_t nameBegin = string( argv[ 0 ] ).find_last_of( "/\\" );
    ToolInfo[ name ] = ( nameBegin == string::npos ? argv[ 0 ] : argv[ 0 ] + nameBegin + 1 );
    size_t extensionBegin = ToolInfo[ name ].rfind( "." );
    if( extensionBegin != string::npos )
      ToolInfo[ name ].erase( extensionBegin );
  }

  FunctionCall< ToolResult() > callInit( ToolInit );
  bool finished = ExceptionCatcher()
                 .SetMessage( "Aborting " + ToolInfo[ name ] )
                 .Run( callInit );
  if( !finished )
    return genericError;
  ToolResult result = callInit.Result();
  if( result != noError )
  {
    cerr << ToolInfo[ name ] << ": Initialization error" << endl;
    return result;
  }
  OptionSet toolOptions;
  for( int i = 1; i < argc; ++i )
    toolOptions.push_back( argv[i] );

  struct options
  {
    bool execute;
    bool help;
    bool version;
    bool bcitest;
    string inputFile;
    string outputFile;
    int bufferSize;
  } options =
  {
    true,
    false,
    false,
    false,
    "",
    "",
    0,
  };

  if( toolOptions.findopt( "-h|-H|--help|-?" ) )
  {
    options.help = true;
    options.execute = false;
  }
  if( toolOptions.findopt( "-v|-V|--version" ) )
  {
    options.version = true;
    options.execute = false;
  }
  options.inputFile = toolOptions.getopt( "-i|-I|--input", "" );
  options.outputFile = toolOptions.getopt( "-o|-O|--output", "" );
  string buffer = toolOptions.getopt( "-b|-B|--buffer", "4096" );
  if( buffer.empty() )
  {
    options.execute = false;
    options.help = true;
  }
  options.bufferSize = ::atoi( buffer.c_str() );

  if( !options.inputFile.empty() )
    if( !::freopen( options.inputFile.c_str(), "rb", stdin ) )
    {
      cerr << "Could not open " << options.inputFile << " for input" << endl;
      result = fileIOError;
    }

  if( !options.outputFile.empty() )
    if( !::freopen( options.outputFile.c_str(), "wb", stdout ) )
    {
      cerr << "Could not open " << options.outputFile << " for output" << endl;
      result = fileIOError;
    }

  if( result == noError )
  {
    if( options.bufferSize < 0 )
      options.bufferSize *= -1;
    int mode = _IOFBF;
    if( options.bufferSize == 0 )
    {
      options.bufferSize = 0;
      mode = _IONBF;
    }
    if( ::setvbuf( stdin, NULL, mode, options.bufferSize )
        ||::setvbuf( stdout, NULL, mode, options.bufferSize ) )
    {
      cerr << "Could not set buffer size to " << options.bufferSize << endl;
      result = fileIOError;
    }
  }

#ifdef HAVE_BIN_MODE
  if( result == noError )
  {
    ::setmode( fileno( stdin ), O_BINARY );
    if( ToolInfo[outputType].empty() || ToolInfo[outputType][0] != 't' )
      ::setmode( fileno( stdout ), O_BINARY );
  }
#endif

  if( result == noError && options.execute )
  {
    FunctionCall< ToolResult( OptionSet&, istream&, ostream& ) >
      callMain( ToolMain, toolOptions, cin, cout );
    bool finished = ExceptionCatcher()
                   .SetMessage( "Aborting " + ToolInfo[ name ] )
                   .Run( callMain );
    if( !finished )
    {
      result = genericError;
    }
    else
    {
      result = callMain.Result();
#if 0
      if( !( in->good() || !in->eof() || result == fileIOError ) )
      {
        cerr << "Illegal data format" << endl;
        result = illegalInput;
      }
#endif
    }
  }

  options.help |= ( result == illegalOption );
  if( options.help )
  {
    ostream& out = ( result == noError ? cout : cerr );
    out << "Usage: " << ToolInfo[ name ] << " [OPTION]\n"
        << "Options are:\n"
        << "\t-h,       --help                Display this help\n"
        << "\t-v,       --version             Output version information\n"
        << "\t-i<file>, --input=<file>        Get input from <file>\n"
        << "\t-o<file>, --output=<file>       Write output to <file>\n"
        << "\t-b<size>, --buffer=<size>       Set IO buffer to <size>\n";
    for( int i = firstOption; ToolInfo[ i ] != ""; ++i )
      out << '\t' << ToolInfo[ i ] << '\n';
    out << '\n' << ToolInfo[ description ] << '\n';
    out.flush();
  }
  if( options.version )
    cout << ToolInfo[ name ] << " " << ToolInfo[ version ] << endl;

  if( !cout )
  {
    cerr << "Error writing to standard output" << endl;
    result = genericError;
  }
  return result;
}