NAME
    BATsh - Bilingual Shell for cmd.exe and bash in one script
    (self-contained)

VERSION
    Version 0.03

SYNOPSIS
      use BATsh;

      # Run a bilingual .batsh script
      BATsh->run('myscript.batsh');
      BATsh->run('myscript.batsh', args => ['arg1', 'arg2']);

      # Run source inline
      BATsh->run_string('echo hello from sh');
      BATsh->run_string("SET MSG=hello\nECHO %MSG%");

      # Interactive REPL
      BATsh->repl();

      # CMD features: pipe, tilde modifiers, SET /P
      BATsh->run_string('ECHO hello | perl -e "while(<STDIN>){chomp;print uc(\$_).chr(10)}"');
      BATsh->run_string("SET /P NAME=Enter name: ");

      # SH features: functions, expansions, pipelines, redirection
      BATsh->run_string(<<'BATSH');
      greet() {
          echo "Hello, \$1"
      }
      greet world
      x=\$(echo hello | perl -e 'while(<STDIN>){chomp;print uc}')
      echo \$x
      echo out > /tmp/out.txt
      BATSH

      # Perl 5.005_03 and later; pure-Perl, no external shell required.

DESCRIPTION
  Executive Summary
    BATsh is a self-contained bilingual shell interpreter written in pure
    Perl. It runs cmd.exe batch syntax and bash/sh syntax in the same script
    file, switching automatically between CMD mode and SH mode on a
    line-by-line basis. No external cmd.exe, bash, or sh is required --
    everything runs inside Perl.

  Mixed-Mode Sample
    The following script demonstrates cmd.exe and bash sections coexisting
    and sharing variables through the common BATsh::Env variable store.

      :: -- CMD section: sets a variable and calls a SH function via bridge --
      @ECHO OFF
      SET LANG=BATsh
      SET COUNT=3

      # -- SH section: reads CMD variables, uses functions and pipeline --
      greet() {
          echo "Hello from $1 (bash/sh mode)"
      }
      greet $LANG
      for i in 1 2 3; do echo "  item $i of $COUNT"; done
      result=$(echo "$LANG" | perl -e 'while(<STDIN>){chomp;print uc}')
      echo "Uppercase: $result"
      echo "log line" >> /tmp/batsh_demo.txt

      :: -- CMD section again: reads variable set by SH side --
      ECHO Back in CMD mode
      ECHO Uppercase result: %result%

    BATsh features (both modes): pipelines (|), I/O redirection (> >> <
    2>&1), variable expansion (${var%pat} ${var^^} ${#var}), functions,
    shift, local.

FULL DESCRIPTION
    BATsh is a self-contained bilingual shell interpreter written in pure
    Perl. It implements both the cmd.exe command set and the sh/bash command
    set entirely in Perl -- no external cmd.exe, bash, or sh is required.

    Scripts are divided into CMD sections (uppercase first token) and SH
    sections (lowercase first token). Both sections share a common variable
    store via BATsh::Env, so variables set in a CMD section are immediately
    visible in the next SH section and vice versa.

CMD MODE
    Any line whose first token is all uppercase (A-Z, 0-9, path chars) is a
    CMD line. CMD sections are executed by BATsh::CMD, which implements:

      ECHO, @ECHO OFF/ON
      SET VAR=value, SET /A expr (arithmetic)
      SET /P VAR=Prompt  (interactive prompt input from STDIN)
      IF "A"=="B" ... ELSE ..., IF /I (case-insensitive), IF NOT
      IF EXIST "path with spaces", IF DEFINED var, IF ERRORLEVEL n
      FOR %%V IN (list) DO ..., FOR /L %%V IN (s,step,e) DO ...
      FOR /F "tokens= delims= skip= eol= usebackq" %%V IN (src) DO ...
      GOTO :label, :label, GOTO :EOF
      CALL :label [args], CALL file.batsh
      SHIFT, SHIFT /N
      SETLOCAL [ENABLEDELAYEDEXPANSION|DISABLEDELAYEDEXPANSION], ENDLOCAL
      CD, DIR, COPY, DEL, MOVE, MKDIR, RMDIR, REN, TYPE
      PAUSE, EXIT [/B] [code], CLS, TITLE, VER, PUSHD, POPD
      cmd1 | cmd2  (pipeline via temporary file)
      &, &&, ||  (sequential, conditional-and, conditional-or)

  Variable Expansion
    "%VAR%" references are expanded before each line is dispatched. Variable
    names are case-insensitive ("SET foo=x" is visible as "%FOO%").

    Inside parenthesised IF and FOR blocks, "%VAR%" is expanded at parse
    time (before any commands in the block run), matching cmd.exe behaviour.
    To see a value updated inside a block, use delayed expansion:

      SETLOCAL ENABLEDELAYEDEXPANSION
      SET X=old
      IF 1==1 (
          SET X=new
          ECHO !X!       &:: prints "new" (delayed)
          ECHO %X%       &:: prints "old" (parse-time)
      )
      ENDLOCAL

  Batch Parameters
    %0 is the script path (absolute); %1..%9 are positional arguments; "%*"
    is all arguments joined by space. "SHIFT" / "SHIFT /N" shifts the
    positional parameters. "CALL :label" saves and restores caller's
    arguments.

    Batch-parameter tilde modifiers expand %0..%9 components:

      %~0    dequote (strip surrounding "...")
      %~f1   full absolute path of %1
      %~d1   drive letter only   (e.g. C:)
      %~p1   directory path only (with trailing /)
      %~n1   filename without extension
      %~x1   extension only       (e.g. .bat)
      %~dp0  drive + directory    (most common usage)
      %~nx1  filename + extension

  Redirection and Compound Commands
      ECHO text > file      stdout overwrite
      ECHO text >> file     stdout append
      prog 2> err.txt       stderr redirect
      & cmd                 sequential execution
      cmd1 && cmd2          run cmd2 only if cmd1 succeeded (ERRORLEVEL 0)
      cmd1 || cmd2          run cmd2 only if cmd1 failed   (ERRORLEVEL != 0)

    The "^" character escapes the next character:

      ECHO a^&b    prints  a&b   (& not treated as compound separator)
      ECHO a^^b    prints  a^b
      ECHO text^   next line is joined (line continuation)

SH MODE
    Any line whose first token contains a lowercase letter is a SH line. SH
    sections are executed by BATsh::SH, which implements:

      VAR=value, export VAR=value, unset VAR
      echo, printf
      if/then/elif/else/fi
      for VAR in list; do ... done
      while condition; do ... done
      until condition; do ... done
      case $var in pattern) ... ;; esac
      test / [ ... ]  (file, string, and integer comparisons)
      cd, pwd, exit, true, false, :, read, shift [N], local VAR=value
      $(( arithmetic )) -- +, -, *, /, %, and $1..$9 inside
      $( command ) and `command`  (command substitution, nested)
      cmd1 | cmd2 [| cmd3 ...]  (pipeline via temporary file)
      cmd1 && cmd2, cmd1 || cmd2, cmd1 ; cmd2  (compound commands)
      > >> < 2> 2>> 2>&1 1>&2  (I/O redirection)
      cmd << DELIM ... DELIM    (here-document; <<-DELIM, <<'DELIM' too)
      cmd &                     (background execution; external commands)
      name() { ... }, function name { ... }  (function definitions)
      $VAR, ${VAR}, $1..$9, $@, $*, $#, $?, $$, $0, $!
      ${VAR:-default}, ${VAR:=default}, ${VAR:+alt}
      ${VAR%pat}, ${VAR%%pat}   -- shortest/longest suffix removal
      ${VAR#pat}, ${VAR##pat}   -- shortest/longest prefix removal
      ${VAR/pat/rep}, ${VAR//pat/rep}  -- first/all substitution
      ${VAR^^}, ${VAR^}, ${VAR,,}, ${VAR,}  -- case conversion
      ${VAR:N:L}, ${VAR:N}  -- substring
      ${#VAR}  -- string length
      source / . file

REQUIREMENTS
    Perl 5.005_03 or later. Core modules only. No external shell required.

BUGS AND LIMITATIONS
    Commands that are not built in -- "FINDSTR", "SORT", "MORE", "CHOICE",
    "TIMEOUT", "XCOPY", "ROBOCOPY" and the like in CMD mode, and any
    non-builtin program in SH mode -- are NOT reimplemented in Perl. They
    are invoked as external programs (via Perl's "system"), so they work
    only where the host operating system provides the corresponding
    executable (e.g. FINDSTR.EXE on Windows). Only the built-in command set
    is guaranteed to run identically on every platform.

    The built-in CMD interpreter does not implement:

    *   Variable substring "%VAR:~n,m%" and substitution "%VAR:str1=str2%"
        expansion.

    *   Dynamic pseudo-variables "%RANDOM%", "%DATE%", "%TIME%", "%CD%",
        "%CMDCMDLINE%", and "%ERRORLEVEL%" used as a variable reference.

    *   "FOR /F" with "usebackq" backtick-quoted commands on Windows (the
        "cmd /c" subprocess path is untested on Windows).

    The built-in SH interpreter does not support:

    *   Arrays, indexed and associative ("arr[i]", "${arr[@]}",
        "declare -A").

    *   Filename (pathname) globbing such as "echo *.txt" or "for f in
        *.pl". The "*", "?" and "[abc]" metacharacters are honoured in
        "case" patterns and in "${VAR%pat}" / "${VAR#pat}" expansion only,
        not for expanding filenames on the command line.

    *   Tilde expansion "~/path" and "~user" (only "cd" with no argument
        uses "$HOME").

    *   Brace expansion "{a,b}" and "{1..5}".

    *   Here-strings ("<<< word") and process substitution ("<(cmd)",
        ">(cmd)").

    *   The shell options "set -e", "set -u", "set -x", and the builtins
        "trap", "getopts", "select", "alias", "declare"/"typeset", "eval"
        and "exec".

    Common to both modes: a parenthesised group "( ... )" does not run in a
    separate sub-shell; it shares the one variable store, so there is no
    variable-scope isolation.

    Here-documents ("<<", "<<-", "<<'DELIM'") ARE supported on STDIN, with
    these limitations:

    *   Recognised only in SH mode; "<<" has no meaning in CMD mode.

    *   One here-document per command line only (no "cmd <<A <<B").

    *   Here-strings ("<<< word") are not supported.

    *   Combining a here-document with a pipeline or compound operator on
        the same line is best-effort only; use a separate command.

    *   The closing delimiter must be on a line by itself and match
        exactly (after tab stripping for "<<-").

    Background execution (a trailing "&") IS supported in SH mode, with
    these limitations:

    *   Applies to external commands only. A trailing "&" on a built-in, a
        defined function, a variable assignment, or a control keyword is
        ignored and the command runs in the foreground. In CMD mode "&"
        keeps its cmd.exe meaning as a sequential separator (unchanged).

    *   Only a trailing "&" is recognised; a mid-line "&" (e.g. "a & b")
        is not supported. An "&" inside "&&", in ">&"/"2>&1" fd
        duplication, in quotes, or escaped as "\&" is not background.

    *   No job control: "jobs", "wait", "wait %n", "fg", "bg" and "%n"
        job specifications are not implemented; signals are not delivered
        to background jobs.

    *   A backgrounded pipeline or compound list is delegated as a unit to
        the OS shell after BATsh expands variables and substitutions, so
        its redirections and operators follow OS-shell rules.

    *   On a successful launch "$?" is 0; the job's own exit status is not
        awaited. "$!" holds the most recent background PID (empty before
        any job). On Win32 the job is spawned via "system(1, ...)"; on
        Unix it is started through /bin/sh without using a Perl fork.

    Pipeline ("|"), I/O redirection (">" ">>" "<" "2>" "2>>" "2>&1"),
    compound commands ("&&" "||" ";"), and function definitions are all
    supported.

    Section boundary detection is token-based (uppercase vs. lowercase first
    token). Mixed-case first tokens are treated as SH.

    Please report bugs via the issue tracker:
    <https://github.com/ina-cpan/BATsh/issues>

EXAMPLES
    The eg/ directory contains runnable example scripts:

      eg/00_hello.pl                Minimal Perl driver calling BATsh->run
      eg/01_hello.batsh             Hello world in both modes
      eg/02_env_bridge.batsh        Environment-variable bridge (CMD <-> SH)
      eg/03_cmd_features.batsh      CMD-mode features and parameter modifiers
      eg/04_sh_features.batsh       SH-mode features and expansions
      eg/05_cmd_comprehensive.batsh Comprehensive CMD-mode tour
      eg/06_sh_comprehensive.batsh  Comprehensive SH-mode tour
      eg/07_mixed_comprehensive.batsh  Mixed CMD/SH comprehensive tour

    Run a .batsh example with:

      perl -Ilib -MBATsh -e "BATsh->run(shift)" eg/01_hello.batsh

SEE ALSO
    BATsh::CMD, BATsh::SH, BATsh::Env

AUTHOR
    INABA Hitoshi <ina.cpan@gmail.com>

LICENSE
    This software is free software; you can redistribute it and/or modify it
    under the same terms as Perl itself.

