void __fastcall Usage(TConsole * Console)
{
  Console->PrintLine(FORMAT(L"WinSCP, %s", (Configuration->VersionStr)));
  UnicodeString Copyright =
    ReplaceText(LoadStr(WINSCP_COPYRIGHT), L"©", L"(c)");
  Console->PrintLine(Copyright);
  Console->PrintLine();
  Console->PrintLine(LoadStr(USAGE_SYNTAX_LABEL));

  if (!Console->CommandLineOnly())
  {
    PrintUsageSyntax(Console, L"site|workspace|folder");
    PrintUsageSyntax(Console, L"(sftp|scp|ftp[es]|dav[s]|s3)://[user[:password]@]host[:port][/path/[file]]");
    PrintUsageSyntax(Console, FORMAT(L"[mysession] /%s=<name>", (LowerCase(SESSIONNAME_SWICH))));
    PrintUsageSyntax(Console, L"[mysession] /newinstance");
    PrintUsageSyntax(Console, L"[mysession] /edit <path>");
    PrintUsageSyntax(Console, FORMAT(L"[mysession] /%s[=<file>]", (LowerCase(BROWSE_SWITCH))));
    PrintUsageSyntax(Console, FORMAT(L"[mysession] /%s [local_dir] [remote_dir] [/%s]", (LowerCase(SYNCHRONIZE_SWITCH), LowerCase(DEFAULTS_SWITCH))));
    PrintUsageSyntax(Console, FORMAT(L"[mysession] /%s [local_dir] [remote_dir] [/%s]", (LowerCase(KEEP_UP_TO_DATE_SWITCH), LowerCase(DEFAULTS_SWITCH))));
    PrintUsageSyntax(Console, FORMAT(L"[mysession] /%s [path]", (LowerCase(REFRESH_SWITCH))));
    PrintUsageSyntax(Console, FORMAT(L"[mysession] [/privatekey=<file> [/%s=<passphrase>]]", (PassphraseOption)));
    PrintUsageSyntax(Console, L"[mysession] [/hostkey=<fingerprint>]");
    PrintUsageSyntax(Console, FORMAT(L"[mysession] [/clientcert=<file> [/%s=<passphrase>]]", (PassphraseOption)));
    PrintUsageSyntax(Console, L"[mysession] [/certificate=<fingerprint>]");
    PrintUsageSyntax(Console, L"[mysession] [/passive[=on|off]] [/implicit|explicit]");
    PrintUsageSyntax(Console, L"[mysession] [/timeout=<sec>]");
    PrintUsageSyntax(Console, L"[mysession] [/rawsettings setting1=value1 setting2=value2 ...]");
  }
  PrintUsageSyntax(Console,
    UnicodeString(!Console->CommandLineOnly() ? L"[/console] " : L"") +
    FORMAT(L"[/script=<file>] [/%s cmd1...] [/parameter // param1...]", (LowerCase(COMMAND_SWITCH))));
  PrintUsageSyntax(Console,
    FORMAT(L"[/%s=<logfile> [/loglevel=<level>]] [/%s=[<count>%s]<size>]", (LowerCase(LOG_SWITCH), LowerCase(LOGSIZE_SWITCH), LOGSIZE_SEPARATOR)));
  PrintUsageSyntax(Console, L"[/xmllog=<logfile> [/xmlgroups]]");
  PrintUsageSyntax(Console,
    FORMAT(L"[/%s=<inifile>]", (LowerCase(INI_SWITCH))));
  PrintUsageSyntax(Console, FORMAT(L"[/%s config1=value1 config2=value2 ...]", (LowerCase(RAW_CONFIG_SWITCH))));
  PrintUsageSyntax(Console, FORMAT(L"[/%s setting1=value1 setting2=value2 ...]", (LowerCase(RAWTRANSFERSETTINGS_SWITCH))));
  PrintUsageSyntax(Console, L"/batchsettings <site_mask> setting1=value1 setting2=value2 ...");
  PrintUsageSyntax(Console, FORMAT(L"/%s keyfile [/%s=<file>] [/%s] [/%s=<text>]",
    (LowerCase(KEYGEN_SWITCH), LowerCase(KEYGEN_OUTPUT_SWITCH), LowerCase(KEYGEN_CHANGE_PASSPHRASE_SWITCH), LowerCase(KEYGEN_COMMENT_SWITCH))));
  if (!Console->CommandLineOnly())
  {
    PrintUsageSyntax(Console, L"/update");
  }
  PrintUsageSyntax(Console, TProgramParams::FormatSwitch(LowerCase(INFO_SWITCH)));
  PrintUsageSyntax(Console, L"/help");

  Console->PrintLine();

  TSwitchesUsage SwitchesUsage;
  if (!Console->CommandLineOnly())
  {
    RegisterSwitch(SwitchesUsage, L"session", USAGE_SESSION);
    RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(SESSIONNAME_SWICH) + L"=", USAGE_SESSIONNAME);
    RegisterSwitch(SwitchesUsage, L"/newinstance", USAGE_NEWINSTANCE);
    RegisterSwitch(SwitchesUsage, L"/edit", USAGE_EDIT);
    RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(BROWSE_SWITCH), USAGE_BROWSE);
    RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(SYNCHRONIZE_SWITCH), USAGE_SYNCHRONIZE);
    RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(KEEP_UP_TO_DATE_SWITCH), USAGE_KEEPUPTODATE);
    RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(REFRESH_SWITCH), USAGE_REFRESH);
    RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(DEFAULTS_SWITCH), USAGE_DEFAULTS);
    RegisterSwitch(SwitchesUsage, L"/privatekey=", USAGE_PRIVATEKEY);
    RegisterSwitch(SwitchesUsage, L"/hostkey=", USAGE_HOSTKEY);
    RegisterSwitch(SwitchesUsage, L"/clientcert=", USAGE_CLIENTCERT);
    RegisterSwitch(SwitchesUsage, L"/certificate=", USAGE_CERTIFICATE);
    RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(PassphraseOption) + L"=", USAGE_PASSPHRASE);
    RegisterSwitch(SwitchesUsage, L"/passive=", USAGE_PASSIVE);
    RegisterSwitch(SwitchesUsage, L"/implicit", USAGE_IMPLICIT);
    RegisterSwitch(SwitchesUsage, L"/explicit", USAGE_EXPLICIT);
    RegisterSwitch(SwitchesUsage, L"/timeout=", USAGE_TIMEOUT);
    RegisterSwitch(SwitchesUsage, L"/rawsettings", USAGE_RAWSETTINGS);
    RegisterSwitch(SwitchesUsage, L"/console", USAGE_CONSOLE);
  }
  RegisterSwitch(SwitchesUsage, L"/script=", USAGE_SCRIPT);
  RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(COMMAND_SWITCH), USAGE_COMMAND);
  RegisterSwitch(SwitchesUsage, L"/parameter", USAGE_PARAMETER);
  RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(LOG_SWITCH) + L"=", USAGE_LOG);
  RegisterSwitch(SwitchesUsage, L"/loglevel=", USAGE_LOGLEVEL);
  RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(LOGSIZE_SWITCH) + L"=", USAGE_LOGSIZE);
  RegisterSwitch(SwitchesUsage, L"/xmllog=", USAGE_XMLLOG);
  RegisterSwitch(SwitchesUsage, L"/xmlgroups", USAGE_XMLGROUPS);
  RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(INI_SWITCH) + L"=", USAGE_INI);
  RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(RAW_CONFIG_SWITCH), USAGE_RAWCONFIG);
  RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(RAWTRANSFERSETTINGS_SWITCH), USAGE_RAWTRANSFERSETTINGS);
  RegisterSwitch(SwitchesUsage, L"/batchsettings", USAGE_BATCHSETTINGS);
  UnicodeString KeyGenDesc =
    FMTLOAD(USAGE_KEYGEN, (
      TProgramParams::FormatSwitch(LowerCase(KEYGEN_OUTPUT_SWITCH)) + L"=",
      TProgramParams::FormatSwitch(LowerCase(KEYGEN_CHANGE_PASSPHRASE_SWITCH)),
      TProgramParams::FormatSwitch(LowerCase(KEYGEN_COMMENT_SWITCH)) + L"="));
  RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(KEYGEN_SWITCH), KeyGenDesc);
  if (!Console->CommandLineOnly())
  {
    RegisterSwitch(SwitchesUsage, L"/update", USAGE_UPDATE);
  }
  RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(INFO_SWITCH), USAGE_INFO);
  RegisterSwitch(SwitchesUsage, L"/help", USAGE_HELP);

  int MaxSwitchLen = 0;
  TSwitchesUsage::const_iterator Index = SwitchesUsage.begin();
  while (Index != SwitchesUsage.end())
  {
    MaxSwitchLen = std::max(Index->first.Length(), MaxSwitchLen);
    ++Index;
  }

  Index = SwitchesUsage.begin();
  while (Index != SwitchesUsage.end())
  {
    UnicodeString Label =
      UnicodeString(L" ") +
      Index->first +
      UnicodeString::StringOfChar(L' ', MaxSwitchLen - Index->first.Length()) +
      L" ";
    Console->Print(Label);

    const int ConsoleWidth = 80;
    int DescWidth = ConsoleWidth - Label.Length() - 1;

    bool FirstLine = true;
    UnicodeString Desc = Index->second;
    while (!Desc.IsEmpty())
    {
      UnicodeString DescLine = CutToChar(Desc, L'\n', true);
      DescLine = WrapText(DescLine, L"\n", TSysCharSet() << L' ', DescWidth);
      while (!DescLine.IsEmpty())
      {
        UnicodeString DescLineLine = CutToChar(DescLine, L'\n', true);
        if (!FirstLine)
        {
          DescLineLine =
            UnicodeString::StringOfChar(L' ', Label.Length()) +
            DescLineLine;
        }
        FirstLine = false;
        Console->PrintLine(DescLineLine);
      }
    }
    ++Index;
  }

  Console->WaitBeforeExit();
}

void __fastcall Usage(TConsole * Console)
{
  Console->PrintLine(FORMAT(L"WinSCP, %s", (Configuration->VersionStr)));
  UnicodeString Copyright =
    ReplaceText(LoadStr(WINSCP_COPYRIGHT), L"©", L"(c)");
  Console->PrintLine(Copyright);
  Console->PrintLine();
  Console->PrintLine(LoadStr(USAGE_SYNTAX_LABEL));

  if (!Console->CommandLineOnly())
  {
    PrintUsageSyntax(Console, L"site|workspace|folder");
    PrintUsageSyntax(Console, L"(sftp|scp|ftp[es]|dav[s]|s3)://[user[:password]@]host[:port][/path/[file]]");
    PrintUsageSyntax(Console, FORMAT(L"[mysession] /%s=<name>", (LowerCase(SESSIONNAME_SWICH))));
    PrintUsageSyntax(Console, L"[mysession] /newinstance");
    PrintUsageSyntax(Console, L"[mysession] /edit <path>");
    PrintUsageSyntax(Console, FORMAT(L"[mysession] /%s[=<file>]", (LowerCase(BROWSE_SWITCH))));
    PrintUsageSyntax(Console, FORMAT(L"[mysession] /%s [local_dir] [remote_dir] [/%s]", (LowerCase(SYNCHRONIZE_SWITCH), LowerCase(DEFAULTS_SWITCH))));
    PrintUsageSyntax(Console, FORMAT(L"[mysession] /%s [local_dir] [remote_dir] [/%s]", (LowerCase(KEEP_UP_TO_DATE_SWITCH), LowerCase(DEFAULTS_SWITCH))));
    PrintUsageSyntax(Console, FORMAT(L"[mysession] /%s [path]", (LowerCase(REFRESH_SWITCH))));
    PrintUsageSyntax(Console, FORMAT(L"[mysession] [/privatekey=<file> [/%s=<passphrase>]]", (PassphraseOption)));
    PrintUsageSyntax(Console, L"[mysession] [/hostkey=<fingerprint>]");
    PrintUsageSyntax(Console, FORMAT(L"[mysession] [/clientcert=<file> [/%s=<passphrase>]]", (PassphraseOption)));
    PrintUsageSyntax(Console, L"[mysession] [/certificate=<fingerprint>]");
    PrintUsageSyntax(Console, L"[mysession] [/passive[=on|off]] [/implicit|explicit]");
    PrintUsageSyntax(Console, L"[mysession] [/timeout=<sec>]");
    PrintUsageSyntax(Console, L"[mysession] [/rawsettings setting1=value1 setting2=value2 ...]");
  }
  PrintUsageSyntax(Console,
    UnicodeString(!Console->CommandLineOnly() ? L"[/console] " : L"") +
    FORMAT(L"[/script=<file>] [/%s cmd1...] [/parameter // param1...]", (LowerCase(COMMAND_SWITCH))));
  PrintUsageSyntax(Console,
    FORMAT(L"[/%s=<logfile> [/loglevel=<level>]] [/%s=[<count>%s]<size>]", (LowerCase(LOG_SWITCH), LowerCase(LOGSIZE_SWITCH), LOGSIZE_SEPARATOR)));
  PrintUsageSyntax(Console, L"[/xmllog=<logfile> [/xmlgroups]]");
  PrintUsageSyntax(Console,
    FORMAT(L"[/%s=<inifile>]", (LowerCase(INI_SWITCH))));
  PrintUsageSyntax(Console, FORMAT(L"[/%s config1=value1 config2=value2 ...]", (LowerCase(RAW_CONFIG_SWITCH))));
  PrintUsageSyntax(Console, FORMAT(L"[/%s setting1=value1 setting2=value2 ...]", (LowerCase(RAWTRANSFERSETTINGS_SWITCH))));
  PrintUsageSyntax(Console, L"/batchsettings <site_mask> setting1=value1 setting2=value2 ...");
  PrintUsageSyntax(Console, FORMAT(L"/%s keyfile [/%s=<file>] [/%s] [/%s=<text>]",
    (LowerCase(KEYGEN_SWITCH), LowerCase(KEYGEN_OUTPUT_SWITCH), LowerCase(KEYGEN_CHANGE_PASSPHRASE_SWITCH), LowerCase(KEYGEN_COMMENT_SWITCH))));
  if (!Console->CommandLineOnly())
  {
    PrintUsageSyntax(Console, L"/update");
  }
  PrintUsageSyntax(Console, TProgramParams::FormatSwitch(LowerCase(INFO_SWITCH)));
  PrintUsageSyntax(Console, L"/help");

  Console->PrintLine();

  TSwitchesUsage SwitchesUsage;
  if (!Console->CommandLineOnly())
  {
    RegisterSwitch(SwitchesUsage, L"session", USAGE_SESSION);
    RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(SESSIONNAME_SWICH) + L"=", USAGE_SESSIONNAME);
    RegisterSwitch(SwitchesUsage, L"/newinstance", USAGE_NEWINSTANCE);
    RegisterSwitch(SwitchesUsage, L"/edit", USAGE_EDIT);
    RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(BROWSE_SWITCH), USAGE_BROWSE);
    RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(SYNCHRONIZE_SWITCH), USAGE_SYNCHRONIZE);
    RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(KEEP_UP_TO_DATE_SWITCH), USAGE_KEEPUPTODATE);
    RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(REFRESH_SWITCH), USAGE_REFRESH);
    RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(DEFAULTS_SWITCH), USAGE_DEFAULTS);
    RegisterSwitch(SwitchesUsage, L"/privatekey=", USAGE_PRIVATEKEY);
    RegisterSwitch(SwitchesUsage, L"/hostkey=", USAGE_HOSTKEY);
    RegisterSwitch(SwitchesUsage, L"/clientcert=", USAGE_CLIENTCERT);
    RegisterSwitch(SwitchesUsage, L"/certificate=", USAGE_CERTIFICATE);
    RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(PassphraseOption) + L"=", USAGE_PASSPHRASE);
    RegisterSwitch(SwitchesUsage, L"/passive=", USAGE_PASSIVE);
    RegisterSwitch(SwitchesUsage, L"/implicit", USAGE_IMPLICIT);
    RegisterSwitch(SwitchesUsage, L"/explicit", USAGE_EXPLICIT);
    RegisterSwitch(SwitchesUsage, L"/timeout=", USAGE_TIMEOUT);
    RegisterSwitch(SwitchesUsage, L"/rawsettings", USAGE_RAWSETTINGS);
    RegisterSwitch(SwitchesUsage, L"/console", USAGE_CONSOLE);
  }
  RegisterSwitch(SwitchesUsage, L"/script=", USAGE_SCRIPT);
  RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(COMMAND_SWITCH), USAGE_COMMAND);
  RegisterSwitch(SwitchesUsage, L"/parameter", USAGE_PARAMETER);
  RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(LOG_SWITCH) + L"=", USAGE_LOG);
  RegisterSwitch(SwitchesUsage, L"/loglevel=", USAGE_LOGLEVEL);
  RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(LOGSIZE_SWITCH) + L"=", USAGE_LOGSIZE);
  RegisterSwitch(SwitchesUsage, L"/xmllog=", USAGE_XMLLOG);
  RegisterSwitch(SwitchesUsage, L"/xmlgroups", USAGE_XMLGROUPS);
  RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(INI_SWITCH) + L"=", USAGE_INI);
  RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(RAW_CONFIG_SWITCH), USAGE_RAWCONFIG);
  RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(RAWTRANSFERSETTINGS_SWITCH), USAGE_RAWTRANSFERSETTINGS);
  RegisterSwitch(SwitchesUsage, L"/batchsettings", USAGE_BATCHSETTINGS);
  UnicodeString KeyGenDesc =
    FMTLOAD(USAGE_KEYGEN, (
      TProgramParams::FormatSwitch(LowerCase(KEYGEN_OUTPUT_SWITCH)) + L"=",
      TProgramParams::FormatSwitch(LowerCase(KEYGEN_CHANGE_PASSPHRASE_SWITCH)),
      TProgramParams::FormatSwitch(LowerCase(KEYGEN_COMMENT_SWITCH)) + L"="));
  RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(KEYGEN_SWITCH), KeyGenDesc);
  if (!Console->CommandLineOnly())
  {
    RegisterSwitch(SwitchesUsage, L"/update", USAGE_UPDATE);
  }
  RegisterSwitch(SwitchesUsage, TProgramParams::FormatSwitch(INFO_SWITCH), USAGE_INFO);
  RegisterSwitch(SwitchesUsage, L"/help", USAGE_HELP);

  int MaxSwitchLen = 0;
  TSwitchesUsage::const_iterator Index = SwitchesUsage.begin();
  while (Index != SwitchesUsage.end())
  {
    MaxSwitchLen = std::max(Index->first.Length(), MaxSwitchLen);
    ++Index;
  }

  Index = SwitchesUsage.begin();
  while (Index != SwitchesUsage.end())
  {
    UnicodeString Label =
      UnicodeString(L" ") +
      Index->first +
      UnicodeString::StringOfChar(L' ', MaxSwitchLen - Index->first.Length()) +
      L" ";
    Console->Print(Label);

    const int ConsoleWidth = 80;
    int DescWidth = ConsoleWidth - Label.Length() - 1;

    bool FirstLine = true;
    UnicodeString Desc = Index->second;
    while (!Desc.IsEmpty())
    {
      UnicodeString DescLine = CutToChar(Desc, L'\n', true);
      DescLine = WrapText(DescLine, L"\n", TSysCharSet() << L' ', DescWidth);
      while (!DescLine.IsEmpty())
      {
        UnicodeString DescLineLine = CutToChar(DescLine, L'\n', true);
        if (!FirstLine)
        {
          DescLineLine =
            UnicodeString::StringOfChar(L' ', Label.Length()) +
            DescLineLine;
        }
        FirstLine = false;
        Console->PrintLine(DescLineLine);
      }
    }
    ++Index;
  }

  Console->WaitBeforeExit();
}
