Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

scandir help

48 views
Skip to first unread message

ag...@drrob1.com

unread,
Nov 18, 2015, 6:54:53 AM11/18/15
to
I am trying to learn how to use scandir with c++ on Ubuntu 14.04. I
have been able to get the example in the man page working, but this
does not use a filter. I'm trying to understand how to use the filter
param. I found code online and works, but I don't understand what it
is doing and how to make it more flexible. Fragments of my attempts
to understand what is going on remain below. The template of scandir
says it takes a filter function. I have found that if this filter
function does not have a const dirent * param, it will not compile
under gcc. Needless to say, I don't always (are really ever) care
about files that begin with 'a'. I am interested in, say, files that
end in ".txt" but I don't understand what's needed here.

I am coming to C++ after many years of modula-2 programming with
stonybrook m-2. Pointers in m-2 are much easier to understand.
Pointers in C++ are much more complex. This confusion is compounded
by the lack of a proper array type in C++. So pointers are used much
more extensively than in the Wirthian languages.

Thanks,
Rob

#include <sys/types.h>
#include <sys/dir.h>
#include <sys/param.h>
#include <stdio.h>
#include <unistd.h>
#include <cstring>
#include <cstdio>
#include <fstream>
#include <sstream>
#include <iostream>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <ctime>
#include <string>
using namespace std;

char pathname[MAXPATHLEN];
char input[MAXPATHLEN];
int * result;

// From example I found online
int filter(const dirent * filterpattern)
{
return (filterpattern->d_name[0] == 'a');
}

int main()
{
int count,i;
dirent * * files;
dirent * filterpattern;
char * CurrentPathName;

CurrentPathName = getcwd(pathname,MAXPATHLEN);
if (pathname == NULL )
{
cout << "Error getting path" << endl;
exit(0);
}

filterpattern = new dirent; // almost forgot that I have to
allocate this.

cout << "Current Working Directory = " << pathname << ", " <<
CurrentPathName << ", MAXPATHLEN = " << MAXPATHLEN << endl;

count = scandir(".", & files, filter, alphasort);

if (count <= 0)
{
cout << "No files in this directory" << endl;;
exit(0);
}

cout << "Number of files = " << count << endl;
for (i=0; i < count-1; ++i)
{
cout << files[i]->d_name << ", ";
free(files[i]);
}

cout << files[i]->d_name << endl;
free(files);
}

Alf P. Steinbach

unread,
Nov 18, 2015, 8:30:43 AM11/18/15
to
On 11/18/2015 12:54 PM, ag...@drrob1.com wrote:
> I am trying to learn how to use scandir with c++ on Ubuntu 14.04.

Use Boost file system library.


> I have been able to get the example in the man page working, but this
> does not use a filter. I'm trying to understand how to use the filter
> param. I found code online and works, but I don't understand what it
> is doing and how to make it more flexible. Fragments of my attempts
> to understand what is going on remain below. The template of scandir
> says it takes a filter function. I have found that if this filter
> function does not have a const dirent * param, it will not compile
> under gcc. Needless to say, I don't always (are really ever) care
> about files that begin with 'a'. I am interested in, say, files that
> end in ".txt" but I don't understand what's needed here.
>
> I am coming to C++ after many years of modula-2 programming with
> stonybrook m-2. Pointers in m-2 are much easier to understand.
> Pointers in C++ are much more complex. This confusion is compounded
> by the lack of a proper array type in C++. So pointers are used much
> more extensively than in the Wirthian languages.
>
> Thanks,
> Rob
>
> #include <sys/types.h>
> #include <sys/dir.h>
> #include <sys/param.h>

All the above are system specific, non-portable. Avoid that by using
Boost file system library.

> #include <stdio.h>
> #include <unistd.h>
> #include <cstring>
> #include <cstdio>
> #include <fstream>
> #include <sstream>
> #include <iostream>
> #include <cstdlib>
> #include <cctype>
> #include <cmath>
> #include <ctime>
> #include <string>
> using namespace std;
>
> char pathname[MAXPATHLEN];
> char input[MAXPATHLEN];

Global variables are ungood. Raw arrays are ungood. MAXPATHLEN is
system-specific, non-portable; avoid that by using Boost file system
library.


> int * result;

Global variables are ungood. Uninitialized pointers are ungood.


> // From example I found online
> int filter(const dirent * filterpattern)
> {
> return (filterpattern->d_name[0] == 'a');
> }

This returns logical True if the first letter of d_name is "a". For C++
and C99 and later the function result type should be "bool".


> int main()
> {
> int count,i;
> dirent * * files;
> dirent * filterpattern;
> char * CurrentPathName;
>
> CurrentPathName = getcwd(pathname,MAXPATHLEN);
> if (pathname == NULL )
> {
> cout << "Error getting path" << endl;
> exit(0);

Exit value 0 means success. Exit with `EXIT_FAILURE` or a non-zero
system specific value to indicate failure. And in "main", just "return":
that invokes "exit" automatically.


> }
>
> filterpattern = new dirent; // almost forgot that I have to
> allocate this.

No, you don't have to allocate the "dirent" dynamically. You could and
should just declare it as a local variable. But at a higher level, you
shouldn't be doing this at all: avoid all that by using the Boost file
system library.


> cout << "Current Working Directory = " << pathname << ", " <<
> CurrentPathName << ", MAXPATHLEN = " << MAXPATHLEN << endl;

In Windows a "char" based string is not sufficient to hold an arbitrary
path. So for Windows you need to use wide strings. The Boost file system
library does that automatically for you.


> count = scandir(".", & files, filter, alphasort);
>
> if (count <= 0)
> {
> cout << "No files in this directory" << endl;;
> exit(0);
> }
>
> cout << "Number of files = " << count << endl;
> for (i=0; i < count-1; ++i)
> {
> cout << files[i]->d_name << ", ";
> free(files[i]);
> }
>
> cout << files[i]->d_name << endl;
> free(files);
> }
>

Cheers & hth.,

- ALf

ag...@drrob1.com

unread,
Nov 18, 2015, 5:33:48 PM11/18/15
to
On Wed, 18 Nov 2015 14:30:21 +0100, "Alf P. Steinbach"
<alf.p.stein...@gmail.com> wrote:

>On 11/18/2015 12:54 PM, ag...@drrob1.com wrote:
>> I am trying to learn how to use scandir with c++ on Ubuntu 14.04.
>
>Use Boost file system library.
>
>
>Cheers & hth.,
>
>- ALf

Hi ALf.

I look at Boost after you suggested that to me a week or so ago. I
found that to be worse than scandir, for a newbie to C++.

But I will look more into it. For the meantime, scandir is working
for me, and I understand it a little better now.

Thanks,
Rob

Juha Nieminen

unread,
Nov 19, 2015, 4:12:09 AM11/19/15
to
ag...@drrob1.com wrote:
> #include <sys/types.h>
> #include <sys/dir.h>
> #include <sys/param.h>
> #include <stdio.h>
> #include <unistd.h>
> #include <cstring>
> #include <cstdio>
> #include <fstream>
> #include <sstream>
> #include <iostream>
> #include <cstdlib>
> #include <cctype>
> #include <cmath>
> #include <ctime>
> #include <string>

I think you missed a few includes there. There are still plenty in the
standard (and system) library.

--- news://freenews.netfront.net/ - complaints: ne...@netfront.net ---

nobody

unread,
Nov 19, 2015, 5:29:48 PM11/19/15
to
On 2015-11-18 11:54:30 +0000, ag...@drrob1.com said:

> I am trying to learn how to use scandir with c++ on Ubuntu 14.04. I
> have been able to get the example in the man page working, but this
> does not use a filter. I'm trying to understand how to use the filter
> param. I found code online and works, but I don't understand what it
> is doing and how to make it more flexible. Fragments of my attempts
> to understand what is going on remain below. The template of scandir
> says it takes a filter function. I have found that if this filter
> function does not have a const dirent * param, it will not compile
> under gcc. Needless to say, I don't always (are really ever) care
> about files that begin with 'a'. I am interested in, say, files that
> end in ".txt" but I don't understand what's needed here.

If you do it the C way you would use a string comparison:

int filter(const dirent * filterpattern)
{
if (strstr(filterpattern->d_name, ".txt"))
return 1;
else
return 0;
}

The strstr function returns a pointer to the first occurance of 2nd argument
in the first argument, otherwise NULL. Since we don't care about this pointer
we simply flag it as found or not.

>
> I am coming to C++ after many years of modula-2 programming with
> stonybrook m-2. Pointers in m-2 are much easier to understand.
> Pointers in C++ are much more complex. This confusion is compounded
> by the lack of a proper array type in C++. So pointers are used much
> more extensively than in the Wirthian languages.
>
> Thanks,
> Rob

Lots of unnecessary included headers here.

>
> #include <sys/types.h>
> #include <sys/dir.h>
> #include <sys/param.h>
> #include <stdio.h>
> #include <unistd.h>
> #include <cstring>
> #include <cstdio>
> #include <fstream>
> #include <sstream>
> #include <iostream>
> #include <cstdlib>
> #include <cctype>
> #include <cmath>
> #include <ctime>
> #include <string>
> using namespace std;
--^^^^^^^^^^^^^^^^^^^^^
We'll let this one slide.

>
> char pathname[MAXPATHLEN];
> char input[MAXPATHLEN];
> int * result;
>
> // From example I found online
> int filter(const dirent * filterpattern)
> {
> return (filterpattern->d_name[0] == 'a');
> }
>
> int main()
> {
> int count,i;
> dirent * * files;
> dirent * filterpattern;
> char * CurrentPathName;
>
> CurrentPathName = getcwd(pathname,MAXPATHLEN);
> if (pathname == NULL )
-------^^^^^^^^^
I think you meant to write CurrentPathName not pathname here.

> {
> cout << "Error getting path" << endl;
> exit(0);
> }


filterpattern is unused and not needed, discard this line and the declaration.

Jorgen Grahn

unread,
Nov 21, 2015, 8:25:28 AM11/21/15
to
On Wed, 2015-11-18, Alf P. Steinbach wrote:
> On 11/18/2015 12:54 PM, ag...@drrob1.com wrote:
>> I am trying to learn how to use scandir with c++ on Ubuntu 14.04.
>
> Use Boost file system library.
>
>> I have been able to get the example in the man page working, but this
>> does not use a filter. I'm trying to understand how to use the filter
>> param. I found code online and works, but I don't understand what it
>> is doing and how to make it more flexible. Fragments of my attempts
>> to understand what is going on remain below. The template of scandir
>> says it takes a filter function. I have found that if this filter
>> function does not have a const dirent * param, it will not compile
>> under gcc. Needless to say, I don't always (are really ever) care
>> about files that begin with 'a'. I am interested in, say, files that
>> end in ".txt" but I don't understand what's needed here.
>>
>> I am coming to C++ after many years of modula-2 programming with
>> stonybrook m-2. Pointers in m-2 are much easier to understand.
>> Pointers in C++ are much more complex. This confusion is compounded
>> by the lack of a proper array type in C++. So pointers are used much
>> more extensively than in the Wirthian languages.

I don't remember much of Modula-2 (last touched it 25 years ago) but
check out std::vector and the idea behind iterators.

>> #include <sys/types.h>
>> #include <sys/dir.h>
>> #include <sys/param.h>
>
> All the above are system specific, non-portable. Avoid that by using
> Boost file system library.

On the other hand, if you're on Unix, have no plans to support
Windows, check the manual pages for e.g. Linux-specific behavior --
then using them means using well-understood and documented interfaces.

One drawback is that those interfaces are expressed in terms of C, not
C++ -- that's surely one reason to use Boost instead, even if you can
assume POSIX.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
0 new messages