The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Win32::CommandLine - Retrieve and reparse the Win32 command line

VERSION

our $VERSION = qv(qw$Version: 0.5.5.614 $[1])

SYNOPSIS

        @ARGV = Win32::CommandLine::argv() if eval { require Win32::CommandLine; };

        _or_

        use Win32::CommandLine qw( command_line );
        my $commandline = command_line();
        ...

DESCRIPTION

This module is used to reparse the Win32 command line, automating better quoting and globbing of the command line. Globbing is full bash POSIX compatible globbing, including subshell expansions. With the use of the companion script (xx.bat) and doskey for macro aliasing, you can add fully implemented, bash compatible, string quoting/expansion and file globbing to any Win32 executable.

This module is compatible with both cmd.exe and 4nt/tcc/tcmd shells, and can be used to add better parsing and bash glob expansion to any external command (by using the included xx.bat batch script).

CMD.EXE

    doskey type=call xx type $*
    type [a-c]*.pl
    doskey perl=call xx perl $*
    perl -e 'print "test"'              [would otherwise FAIL]

4NT/TCC/TCMD

    alias type=call xx type
    type [a-c]*.pl
    .
    alias perl=call xx perl
    perl -e 'print "test"'              [would otherwise FAIL]

Note that bash compatible character expansion and globbing is available, including glob meta-notations such as "a[bc]*" or "foo.{bat,pl,exe,o}".

Command line string/character expansion

  '...'    literal (no escapes and no globbing within quotes)
  "..."    literal (no escapes and no globbing within quotes)
  $'...'   string including all ANSI C string escapes (see NOTE); no globbing within quotes
  $"..."   literal (no escapes and no globbing within quotes) [same as "..."]
  $( ... ) subshell expansion [subshell commandline is _not_ expanded]
  $("...") subshell expansion (quotes removed) [subshell commandline is _not_ expanded]

NOTE: ANSI C string escapes are (\a, \b, \e, \f, \n, \r, \t, \v, \\, \', \n{1,3}, \xh{1,2}, \cx; all other escaped characters: \<x> =>\<x>).

GLOB META CHARACTERS

  \       Quote the next metacharacter
  []      Character class
  {}      Multiple pattern
  *       Match any string of characters
  ?       Match any single character
  ~       Current user home directory
  ~USER   User NAME home directory
  ~TEXT   Environment variable named ~TEXT (aka $ENV{~TEXT}) [overrides ~USER expansion]

The metanotation a{b,c,d}e is a shorthand for abe ace ade. Left to right order is preserved, with results of matches being sorted separately at a low level to preserve this order.

INSTALLATION

To install this module, run the following commands:

    perl Build.PL
    ./Build
    ./Build test
    ./Build install

Or, if you're on a platform (like DOS or Windows) that doesn't require the "./" notation, you can do this:

    perl Build.PL
    Build
    Build test
    Build install

Alternatively, the standard make idiom is also available (though it is deprecated):

    perl Makefile.PL
    make
    make test
    make install

(On Windows platforms you should use nmake instead.)

Note that the Makefile.PL script is just a pass-through, and Module::Build is still ultimately required for installation. Makefile.PL will offer to download and install Module::Build if it is missing from your current installation.

PPM installation bundles should also be available in the standard PPM repositories (i.e. ActiveState, trouchelle.com [http://trouchelle.com/ppm/package.xml]).

Note: On ActivePerl installations, "./Build install" will do a full installation using ppm (see ppm). During the installation, a PPM package is constructed locally and then subsequently used for the final module install. This allows for uninstalls (using "ppm uninstall MODULE" and also keeps local HTML documentation current.

INTERFACE

SUBROUTINES/METHODS

command_line( )

command_line(): returns $ :: returns the full Win32 command line as a string.

argv( [\%] )

argv( [\%] ): returns @ :: get the current command line and reparse/glob-expand it; returning a new ARGV array

parse( $ [,\%] )

parse( $ [,\%] ): returns @ :: takes a string argument and returns the parsed argument string as an array.

RATIONALE

This began as a simple need to work-around the less-than-stellar COMMAND.COM/CMD.EXE command line parser, just to accomplish more `correct` quotation interpretation. It then grew into a small odyssey: learning XS and how to create a perl module, learning the perl build process and creating a customized build script/environment, researching tools and developing methods for revision control and versioning, learning and creating perl testing processes, and finally learning about PAUSE and perl publishing practices. And, somewhere in the middle, adding some of the bash shell magic to the CMD shell (and, additionally, making it compatible with the excellent [and free] TCC-LE shell from JPSoft [find it at http://jpsoft.com/]).

Some initial attempts were made using Win32::API and Inline::C. For example (Win32::API attempt [caused GPFs]):

    @rem = '--*-Perl-*--
    @echo off
    if "%OS%" == "Windows_NT" goto WinNT
    perl -x -S "%0" %1 %2 %3 %4 %5 %6 %7 %8 %9
    goto endofperl
    :WinNT
    perl -x -S %0 %*
    if NOT "%COMSPEC%" == "%SystemRoot%\system32\cmd.exe" goto endofperl
    if %errorlevel% == 9009 echo You do not have Perl in your PATH.
    if errorlevel 1 goto script_failed_so_exit_with_non_zero_val 2>nul
    goto endofperl
    @rem ';
    #!/usr/bin/perl -w
    #line 15
    #
    use Win32::API;
    #
    Win32::API->Import("kernel32", "LPTSTR GetCommandLine()");
    my $string = pack("Z*", GetCommandLine());
    #
    print "string[".length($string)."] = '$string'\n";
    # ------ padding --------------------------------------------------------------------------------------
    __END__
    :endofperl

Unfortunately, Win32::API and Inline::C were shown to be too fragile at the time (in 2007). Win32::API caused occasional (but reproducible) GPFs, and Inline::C was very brittle on Win32 systems (not compensating for paths with embedded strings). [ See http://www.perlmonks.org/?node_id=625182 for a more full explanation of the problem and initial attempts at a solution. ]

So, an initial XS solution was implemented. And from that point, the lure of bash-like command line parsing led inexorably to the full implementation. The parsing logic is unfortunately still complex, but seems to be holding up under testing.

IMPLEMENTATION and INTERNALS

wrap_GetCommandLine() :: [XS] Use C and Win32 API to get the command line.

DIAGNOSTICS

Pending documentation...

CONFIGURATION AND ENVIRONMENT

Win32::CommandLine requires no configuration files or environment variables.

OPTIONAL Environment Variables

$ENV{NULLGLOB} = 0/1 => overrides default 'nullglob' setting

DEPENDENCIES

Win32::CommandLine requires Carp::Assert for internal error checking and warnings.

The optional modules Win32, Win32::API, Win32::Security::SID, and Win32::TieRegistry are recommended to allow full glob tilde expansions for user home directories (eg, ~administrator expands to C:\Users\Administrator). Expansion of the single tilde (~) has a backup implementation based on %ENV variables, and therefore will still work even without the optional modules.

INCOMPATIBILITIES

None reported.

BUGS AND LIMITATIONS

Please report any bugs or feature requests to bug-Win32-CommandLine@rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Win32-CommandLine. The developers will be notified, and you'll automatically be notified of progress on your bug as any changes are made.

Operational Notes

IMPORTANT NOTE: Special shell characters (shell redirection [ '|', '<', '>' ] and continuation '&') must be DOUBLE-quoted to escape shell interpretation (eg, "foo | bar"). The shell does initial parsing and redirection/continuation (stripping away everything after I/O redirection and continuation characters) before any process can get a look at the command line. So, the special shell characters can only be hidden from shell interpretation by quoting them with double-quote characters.

%<X> is also replaced by the corresponding %ENV variable by the shell before handing the command line off to the OS. So, %% must be used to place single %'s in the command line (eg, perl -e "use Win32::CommandLine; %%x = Win32::CommandLine::_home_paths(); for (sort keys %%x) { print qq{$_ => $x{$_}\n}; }").

Brackets ('{' and '}') and braces ('[' and ']') must be quoted (single or double quotes) to be matched literally. This may be a gotcha for some users, although if the filename has internal spaces, tab expansion of filenames for the standard Win32 shell (cmd.exe) or 4NT/TCC/TCMD will automatically surround the entire path with spaces (which corrects the issue).

Some programs may expect their arguments to maintain their surrounding quotes, but argv() parsing only quotes arguments which require it to maintain equivalence for shell parsing (i.e., those containing spaces, special characters, etc). And, since single quotes have no special meaning to the shell, all arguments which require quoting for correct shell interpretation will be quoted with double-quote characters, even if they were originally quoted with single-quotes. Neither of these issues should be a problem for programs using Win32::CommandLine, but may be an issue for 'legacy' applications which have their command line expanded with xx.bat.

Be careful with backslashed quotes within quoted strings. Note that "foo\" is an unbalanced string containing a double quote. Place the backslash outside of the quotation ("foo"\) or use a double backslash within ("foo\\") to include the backslash it in the parsed token. However, backslashes ONLY need to be doubled when placed prior to a quotation mark ("foo\bar" will work as expected).

Bugs

No bugs have been reported.

SUPPORT

You can find documentation for this module with the perldoc command.

    perldoc Win32::CommandLine

You can also look for further information at:

    * AnnoCPAN: Annotated CPAN documentation
      E<space>
    . http://annocpan.org/dist/Win32-CommandLine
      E<space>
    * CPAN Ratings
      E<space>
      http://cpanratings.perl.org/dist/Win32-CommandLine
      E<space>
    * RT: CPAN's request tracker (aka buglist)
      E<space>
      http://rt.cpan.org/Public/Dist/Display.html?Name=Win32-CommandLine
      E<space>
    * Search CPAN
      E<space>
      http://kobesearch.cpan.org/dist/Win32-CommandLine
      _or_
      http://search.cpan.org/dist/Win32-CommandLine
      E<space>
    * CPANTS: CPAN Testing Service
      E<space>
      [kwalitee] http://cpants.perl.org/dist/kwalitee/Win32-CommandLine
      [ used by] http://cpants.perl.org/dist/used_by/Win32-CommandLine
      E<space>
    * CPANTESTERS: Test results
      E<space>
      http://www.cpantesters.org/show/Win32-CommandLine.html

TODO

Expand and polish the documentation. Add argument/option explanations and examples for interface functions.

TESTING

For additional testing, set the following environment variables to a true value ("true" in the perl sense, meaning non-NULL, non-ZERO value):

TEST_AUTHOR

Perform distribution correctness and quality tests, which are essential prior to a public release.

TEST_FRAGILE

Perform tests which have a specific (i.e., fragile) execution context (eg, network tests to named hosts). These are tests that must be coddled with specific execution contexts or set up on specific machines to complete correctly.

TEST_SIGNATURE

Verify signature is present and correct for the distribution.

TEST_ALL

Perform ALL (non-FRAGILE) additional/optional tests. Given the likelyhood of test failures without special handling, tests marked as 'FRAGILE' are still NOT performed unless TEST_FRAGILE is also true. Additionally, note that the 'build testall' command can be used as an equivalent to setting TEST_ALL to true temporarily, for the duration of the build, followed by a 'build test'.

LICENSE AND COPYRIGHT

  Copyright (c) 2007-2009, Roy Ivy III <rivy[at]cpan[dot]org>. All rights reserved.

This module is free software; you can redistribute it and/or modify it under the Perl Artistic License v2.0 (see http://opensource.org/licenses/artistic-license-2.0.php).

DISCLAIMER OF WARRANTY

  THIS PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS"
  AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT
  ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED
  BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT,
  INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF
  THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

  [REFER TO THE FULL LICENSE FOR EXPLICIT DEFINITIONS OF ALL TERMS.]

ACKNOWLEDGEMENTS

Thanks to BrowserUK and syphilis (aka SISYPHUS on CPAN) for some helpful ideas (including an initial XS starting point for the module) during a discussion on PerlMonks (see http://www.perlmonks.org/?node_id=625182).

AUTHOR

Roy Ivy III <rivy[at]cpan[dot]org>