Enabling globbing in a console Win32 application
"Globbing" can be also described as an act of expanding the filename wildcards supplied in the command-line of a console application.
Let's suppose we have a small command-line application that performs some operation on files supplied as arguments in the command-line.
#include <iostream>
#include <string>
int main(int argc, char **argv) {
for(int i = 1; i < argc; i++) {
std::cout << argv[i] << "\n";
}
return 0;
}
When running this application on MacOS X, or Linux, or any other platform that
uses an power-user-grade shell, like bash
, tcsh
or zsh
, invocation of this
program with a wildcard in the argument would result in something like this:
$ touch file{1,2,3}.bin
$ g++ test.cpp -o test
$ ./test *.bin
file1.bin
file2.bin
file3.bin
This behavior is a result of an implicit globbing
that occurs before the
actual invocation of our program, and is performed by the shell automatically.
For example, you can turn off globbing, at least in zsh:
$ noglob ./test *.bin
*.bin
This will probably be quite useless in most cases, but even if you actually
expect to have this behavior in your application, you can also expand supplied
wildcards later by using the glob(3)
function, which is available on MacOS X,
Linux, BSDs and other systems with APIs compatible more or less with 4.4BSD.
On Windows however, the "shell" in the form of cmd.exe
doesn't seem to support
such feature. Every console application is expected to perform globbing by itself, but
which API to use? There's one option to use _findfirst
, or FindFirst
, which
should work, and another method that uses PathMatchSpec WinAPI
function, but using them is not portable and is actually an extra work that
needs to be done (not cool, right?).
It turns out that the solution is pretty simple, although definitely not
intuitive. You can link setargv.obj
file (available in your standard Visual
Studio distribution) to your project, and the main()
function will
automatically contain already globbed filenames, so no wildcard preprocessing
will be needed.
If you're using CMake
, you can try something like this:
cmake_minimum_required(VERSION 3.0.0)
set(SRC test.cpp)
add_executable(testapp ${SRC})
# Linking setargv.obj to automatically enable globbing
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} setargv.obj")
If you're not using CMake, have you considered trying it?
If you need unicode support, try linking wsetargv.obj
file instead. After
linking the file, you can test it:
C:\dir>testapp.exe *.bin
file1.bin
file2.bin
file3.bin
It works, and we didn't even use MinGW!