tags:

views:

672

answers:

5

Is there a smooth way to glob in C or C++ in Windows?

E.g., myprogram.exe *.txt sends my program an ARGV list that has...ARGV[1]=*.txt in it.

I would like to be able to have a function (let's call it readglob) that takes a string and returns a vector of strings, each containing a filename.

This way, if I have files a.txt b.txt c.txt in my directory and readglob gets an argument *.txt, it returns the above filelist.

//Prototype of this hypothetical function.
vector<string> readglob(string);

Does such exist?

A: 

Ehw. I had to implement something like this in ANSI C about 15 years ago. Start with the ANSI opendir/readdir routines, I guess. Globs aren't exactly RegExs, so you will have to implement your own filtering.

Roboprog
According to http://stackoverflow.com/questions/883594/microsoft-visual-studio-opendir-and-readdir-how opendir/readir aren't in Visual Studio.
Paul Nathan
Drat! those must be POSIX, not ANSI. Whatever happened to the Win NT POSIX layer???
Roboprog
+1  A: 

there was talk about having it in Boost::filesystem but it was dropped in favor of using the boost::regex.

For win32 specific (MFC) you can use the CFileFind class

Martin Beckett
Paul Nathan
Seems that for non-MFC stuff, you can use FindFirstFile and friends to do it with straight win32 code.
Evan Teran
MFC is mostly wrappers around win32 calls, couldn't remember the FindFirstFile(), it all comes back to me now.
Martin Beckett
A: 

There may be a better way now, but last time I had to deal with this problem I ended up including Henry Spencer's regex library statically linked into my program (his library is BSD licensed), and then I made a wrapper class that converted the user's glob-expressions into regular expressions to feed to the regex code. You can view/grab the wrapper class here if you like.

Once you have those parts in place, the final thing to do is actually read the directory, and pass each entry name into the matching function to see if it matches the expression or not. The filenames that match, you add to your vector; the ones that don't you discard. Reading the directory is fairly straightforward to do using the DOS _findfirst() and _findnext() functions, but if you want a nicer C++ interface I have a portable wrapper class for that also...

Jeremy Friesner
+1  A: 

This is very Windows-specific. I don't know how you'd write this to be cross-platform. But I've used this in Windows programs and it works well for me.

// Change to the specified working directory
string path;
cout << "Enter the path to report: ";
cin >> path;
_chdir(path.c_str());

// Get the file description
string desc;
cout << "Enter the file description: ";
cin >> desc;

// List the files in the directory
intptr_t file;
_finddata_t filedata;
file = _findfirst(desc.c_str(),&filedata);
if (file != -1)
{
  do
  {
    cout << filedata.name << endl;
    // Or put the file name in a vector here
  } while (_findnext(file,&filedata) == 0);
}
else
{
  cout << "No described files found" << endl;
}
_findclose(file);
Daedylus
don't use pre/code tags, instead just highlight the code and click on the button with 1/0's on it. It'll make it show up as code.
Evan Teran
Thanks, Evan. That's the first time I've put code in an answer. Obviously...
Daedylus
+1 for code; I've selected Michael's answer because it's much simpler. :-)
Paul Nathan
+6  A: 

Link with setargv.obj (or wsetargv.obj) and argv[] will be globbed for you similar to how the Unix shells do it:

I can't vouch for how well it does it though.

Michael Burr
Terribly non-cross-platform, but it's easy and it Just Works.
Paul Nathan
It doesn't have to be cross-platform because only Win32 has this problem! Great tip.
Greg Hewgill
Just tried it myself. Works like a champ. Couldn't be easier.
T.E.D.
@T.E.D. - good to hear.
Michael Burr