text: #!/usr/bin/python
  
  # Copyright 2001 Dave Abrahams
  # Copyright 2011 Steven Watanabe
  # Distributed under the Boost Software License, Version 1.0.
  # (See accompanying file LICENSE.txt or copy at
  # https://www.bfgroup.xyz/b2/LICENSE.txt)
  
  # Tests Windows command line construction.
  #
  # Note that the regular 'echo' is an internal shell command on Windows and
  # therefore can not be called directly as a standalone Windows process.
  
  import BoostBuild
  import os
  import re
  import sys
  
  
  executable = sys.executable.replace("\\", "/")
  if " " in executable:
      executable = '"%s"' % executable
  
  
  def string_of_length(n):
      if n <= 0:
          return ""
      n -= 1
      y = ['', '$(1x10-1)', '$(10x10-1)', '$(100x10-1)', '$(1000x10-1)']
      result = []
      for i in reversed(range(5)):
          x, n = divmod(n, 10 ** i)
          result += [y[i]] * x
      result.append('x')
      return " ".join(result)
  
  
  #   Boost Jam currently does not allow preparing actions with completely empty
  # content and always requires at least a single whitespace after the opening
  # brace in order to satisfy its Boost Jam language grammar rules.
  def test_raw_empty():
      whitespace_in = "  \n\n\r\r\v\v\t\t   \t   \r\r   \n\n"
  
      #   We tell the testing system to read its child process output as raw
      # binary data but the bjam process we run will read its input file and
      # write out its output as text, i.e. convert all of our "\r\n" sequences to
      # "\n" on input and all of its "\n" characters back to "\r\n" on output.
      # This means that any lone "\n" input characters not preceded by "\r" will
      # get an extra "\r" added in front of it on output.
      whitespace_out = whitespace_in.replace("\r\n", "\n").replace("\n", "\r\n")
  
      t = BoostBuild.Tester(["-d2", "-d+4"], pass_toolset=0,
          use_test_config=False)
      t.write("file.jam", """\
  actions do_empty {%s}
  JAMSHELL = %% ;
  do_empty all ;
  """ % (whitespace_in))
      t.run_build_system(["-ffile.jam"], universal_newlines=False)
      t.expect_output_lines("do_empty all")
      t.expect_output_lines("Executing raw command directly", False)
      if "\r\n%s\r\n" % whitespace_out not in t.stdout():
          BoostBuild.annotation("failure", "Whitespace action content not found "
              "on stdout.")
          t.fail_test(1, dump_difference=False)
      t.cleanup()
  
  
  def test_raw_nt(n=None, error=False):
      t = BoostBuild.Tester(["-d1", "-d+4"], pass_toolset=0,
          use_test_config=False)
  
      cmd_prefix = "%s -c \"print('XXX: " % executable
      cmd_suffix = "')\""
      cmd_extra_length = len(cmd_prefix) + len(cmd_suffix)
  
      if n == None:
          n = cmd_extra_length
  
      data_length = n - cmd_extra_length
      if data_length < 0:
          BoostBuild.annotation("failure", """\
  Can not construct Windows command of desired length. Requested command length
  too short for the current test configuration.
      Requested command length: %d
      Minimal supported command length: %d
  """ % (n, cmd_extra_length))
          t.fail_test(1, dump_difference=False)
  
      #   Each $(Xx10-1) variable contains X words of 9 characters each, which,
      # including spaces between words, brings the total number of characters in
      # its string representation to X * 10 - 1 (X * 9 characters + (X - 1)
      # spaces).
      t.write("file.jam", """\
  ten = 0 1 2 3 4 5 6 7 8 9 ;
  
  1x10-1 = 123456789 ;
  10x10-1 = $(ten)12345678 ;
  100x10-1 = $(ten)$(ten)1234567 ;
  1000x10-1 = $(ten)$(ten)$(ten)123456 ;
  
  actions do_echo
  {
      %s%s%s
  }
  JAMSHELL = %% ;
  do_echo all ;
  """ % (cmd_prefix, string_of_length(data_length), cmd_suffix))
      if error:
          expected_status = 1
      else:
          expected_status = 0
      t.run_build_system(["-ffile.jam"], status=expected_status)
      if error:
          t.expect_output_lines("Executing raw command directly", False)
          t.expect_output_lines("do_echo action is too long (%d, max 32766):" % n
              )
          t.expect_output_lines("XXX: *", False)
      else:
          t.expect_output_lines("Executing raw command directly")
          t.expect_output_lines("do_echo action is too long*", False)
  
          m = re.search("^XXX: (.*)$", t.stdout(), re.MULTILINE)
          if not m:
              BoostBuild.annotation("failure", "Expected output line starting "
                  "with 'XXX: ' not found.")
              t.fail_test(1, dump_difference=False)
          if len(m.group(1)) != data_length:
              BoostBuild.annotation("failure", """Unexpected output data length.
      Expected: %d
      Received: %d""" % (n, len(m.group(1))))
              t.fail_test(1, dump_difference=False)
  
      t.cleanup()
  
  
  def test_raw_to_shell_fallback_nt():
      t = BoostBuild.Tester(["-d1", "-d+4"], pass_toolset=0,
          use_test_config=False)
  
      cmd_prefix = '%s -c print(' % executable
      cmd_suffix = ')'
  
      t.write("file_multiline.jam", """\
  actions do_multiline
  {
      echo one
  
  
      echo two
  }
  JAMSHELL = % ;
  do_multiline all ;
  """)
      t.run_build_system(["-ffile_multiline.jam"])
      t.expect_output_lines("do_multiline all")
      t.expect_output_lines("one")
      t.expect_output_lines("two")
      t.expect_output_lines("Executing raw command directly", False)
      t.expect_output_lines("Executing using a command file and the shell: "
          "cmd.exe /Q/C")
  
      t.write("file_redirect.jam", """\
  actions do_redirect { echo one > two.txt }
  JAMSHELL = % ;
  do_redirect all ;
  """)
      t.run_build_system(["-ffile_redirect.jam"])
      t.expect_output_lines("do_redirect all")
      t.expect_output_lines("one", False)
      t.expect_output_lines("Executing raw command directly", False)
      t.expect_output_lines("Executing using a command file and the shell: "
          "cmd.exe /Q/C")
      t.expect_addition("two.txt")
  
      t.write("file_pipe.jam", """\
  actions do_pipe
  {
      echo one | echo two
  }
  JAMSHELL = % ;
  do_pipe all ;
  """)
      t.run_build_system(["-ffile_pipe.jam"])
      t.expect_output_lines("do_pipe all")
      t.expect_output_lines("one*", False)
      t.expect_output_lines("two")
      t.expect_output_lines("Executing raw command directly", False)
      t.expect_output_lines("Executing using a command file and the shell: "
          "cmd.exe /Q/C")
  
      t.write("file_single_quoted.jam", """\
  actions do_single_quoted { %s'5>10'%s }
  JAMSHELL = %% ;
  do_single_quoted all ;
  """ % (cmd_prefix, cmd_suffix))
      t.run_build_system(["-ffile_single_quoted.jam"])
      t.expect_output_lines("do_single_quoted all")
      t.expect_output_lines("5>10")
      t.expect_output_lines("Executing raw command directly")
      t.expect_output_lines("Executing using a command file and the shell: "
          "cmd.exe /Q/C", False)
      t.expect_nothing_more()
  
      t.write("file_double_quoted.jam", """\
  actions do_double_quoted { %s"5>10"%s }
  JAMSHELL = %% ;
  do_double_quoted all ;
  """ % (cmd_prefix, cmd_suffix))
      t.run_build_system(["-ffile_double_quoted.jam"])
      t.expect_output_lines("do_double_quoted all")
      # The difference between this example and the similar previous one using
      # single instead of double quotes stems from how the used Python executable
      # parses the command-line string received from Windows.
      t.expect_output_lines("False")
      t.expect_output_lines("Executing raw command directly")
      t.expect_output_lines("Executing using a command file and the shell: "
          "cmd.exe /Q/C", False)
      t.expect_nothing_more()
  
      t.write("file_escaped_quote.jam", """\
  actions do_escaped_quote { %s\\"5>10\\"%s }
  JAMSHELL = %% ;
  do_escaped_quote all ;
  """ % (cmd_prefix, cmd_suffix))
      t.run_build_system(["-ffile_escaped_quote.jam"])
      t.expect_output_lines("do_escaped_quote all")
      t.expect_output_lines("5>10")
      t.expect_output_lines("Executing raw command directly", False)
      t.expect_output_lines("Executing using a command file and the shell: "
          "cmd.exe /Q/C")
      t.expect_nothing_more()
  
      t.cleanup()
  
  
  ###############################################################################
  #
  # main()
  # ------
  #
  ###############################################################################
  
  if os.name == 'nt':
      test_raw_empty()
  
      #   Can not test much shorter lengths as the shortest possible command line
      # line length constructed in this depends on the runtime environment, e.g.
      # path to the Panther executable running this test.
      test_raw_nt()
      test_raw_nt(255)
      test_raw_nt(1000)
      test_raw_nt(8000)
      test_raw_nt(8191)
      test_raw_nt(8192)
      test_raw_nt(10000)
      test_raw_nt(30000)
      test_raw_nt(32766)
      #   CreateProcessA() Windows API places a limit of 32768 on the allowed
      # command-line length, including a trailing Unicode (2-byte) nul-terminator
      # character.
      test_raw_nt(32767, error=True)
      test_raw_nt(40000, error=True)
      test_raw_nt(100001, error=True)
  
      test_raw_to_shell_fallback_nt()