From: frank on
Hello again comp.unix.programer,gnu.gcc.help

I would like to develop a small C utility that does something that a
mortensen child can use. If I don't get it done before the end of
january, then it's not a x-mas gift. I bought _Crossing the Threshold
of Hope_ for Alan and have a thumbdrive of music for Robyn.

So this is to make a source listing and not much else. I'll do that
after the sig so you won't have to read it unless you want to.

What follows is the readdir() I understand best and then working code
from unleashed that has a 2-d resizable array.

Jens Thoerring has given me the best design idea that I have right now,
but if you think you have a better one given the source below, then I'm
all ears.

Thanks for your constructive comment and cheers,


--
frank





#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <limits.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>

#define PATH_SIZE 300

unsigned
process_directory (char *theDir)
{
DIR *dir = NULL;
struct dirent entry;
struct dirent *entryPtr = NULL;
int retval = 0;
unsigned count = 0;
char pathName[PATH_SIZE + 1];

/* Open the given directory, if we can. */
dir = opendir (theDir);
if (dir == NULL)
{
printf ("Error opening %s: %s", theDir, strerror (errno));
return 0;
}


retval = readdir_r (dir, &entry, &entryPtr);
while (entryPtr != NULL)
{
struct stat entryInfo;

if ((strncmp (entry.d_name, ".", PATH_SIZE) == 0) ||
(strncmp (entry.d_name, "..", PATH_SIZE) == 0))
{
/* Short-circuit the . and .. entries. */
retval = readdir_r (dir, &entry, &entryPtr);
continue;
}

(void) strncpy (pathName, theDir, PATH_SIZE);
(void) strncat (pathName, "/", PATH_SIZE);
(void) strncat (pathName, entry.d_name, PATH_SIZE);

if (lstat (pathName, &entryInfo) == 0)
{
/* stat() succeeded, let's party */
count++;

if (S_ISDIR (entryInfo.st_mode))
{ /* directory */
printf ("processing %s/\n", pathName);
count += process_directory (pathName);
}
else if (S_ISREG (entryInfo.st_mode))
{ /* regular file */
printf ("\t%s has %lld bytes\n",
pathName, (long long) entryInfo.st_size);
}
else if (S_ISLNK (entryInfo.st_mode))
{ /* symbolic link */
char targetName[PATH_SIZE + 1];
if (readlink (pathName, targetName, PATH_SIZE) != -1)
{
printf ("\t%s -> %s\n", pathName, targetName);
}
else
{
printf ("\t%s -> (invalid symbolic link!)\n", pathName);
}
}
}
else
{
printf ("Error statting %s: %s\n", pathName, strerror (errno));
}

retval = readdir_r (dir, &entry, &entryPtr);
}

/* Close the directory and return the number of entries. */
(void) closedir (dir);
return count;
}

int
main (void)
{
process_directory ("/etc/");
return EXIT_SUCCESS;
}

// gcc -D_GNU_SOURCE -Wall -Wextra rd3.c -o out


end rd3.c. strarr2.h:

// strarr2.h - header for string array demo


#ifndef STRARR_H__
#define STRARR_H__

void FreeStrArray(char **, size_t );
char **AllocStrArray(size_t , size_t);
int ResizeOneString(char **,
size_t ,
size_t );
int AddFilesToStrArray(char ***,
size_t ,
int ,
size_t );
int ConsolidateStrArray(char **,
size_t );

#endif





end strarr2.h begin strarr2.c:




#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include "strarr2.h"

void FreeStrArray(char **Array, size_t NumFiles)
{
size_t index;

if(Array != NULL)
{
for(index = 0; index < NumFiles; index++)
{
if(Array[index] != NULL)
{
free(Array[index]);
}
}
free(Array);
}
}

char **AllocStrArray(size_t NumFiles, size_t Width)
{
char **Array = NULL;
size_t index;
int Success = 1;

/* allocating 0 bytes is not a great idea, and
* represents a logic error.
*/
assert(NumFiles > 0);
assert(Width > 0);

/* Just in case the zero allocation is NOT caught
* in testing, we'll check for it here.
*/
if(NumFiles > 0 && Width > 0)
{
Array = malloc(NumFiles * sizeof *Array);
if(Array != NULL)
{
for(index = 0; index < NumFiles; index++)
{
Array[index] = malloc(Width * sizeof *Array[index]);
if(NULL == Array[index])
{
Success = 0;
}
else
{
/* Making this into an empty string is a quick
* op which will almost invariably be The Right
* Thing and can never be The Wrong Thing, so
* we might as well do it.
*/
Array[index][0] = '\0';
}
}
/* If any inner allocation failed,
* we should clean up.
*/
if(1 != Success)
{
FreeStrArray(Array, NumFiles);
Array = NULL;
}
}
}

return Array;
}

int ResizeOneString(char **Array,
size_t index,
size_t NewSize)
{
char *p;
int Success = 1;

assert(Array != NULL);

p = realloc(Array[index], NewSize);
if(p != NULL)
{
Array[index] = p;
}
else
{
Success = 0;
}

return Success;
}

int AddFilesToStrArray(char ***ArrayPtr,
size_t OldNumFiles,
int NumFilesToAdd,
size_t InitWidth)
{
char **p;
int Success = 1;
int index;
int OldFiles;

OldFiles = (int)OldNumFiles;
if(NumFilesToAdd < 0)
{
for(index = OldFiles - 1;
index >= OldFiles + NumFilesToAdd;
index--)
{
free((*ArrayPtr)[index]);
}
}

p = realloc(*ArrayPtr,
(OldFiles + NumFilesToAdd) *
sizeof(**ArrayPtr));

if(p != NULL)
{
*ArrayPtr = p;

for(index = OldFiles;
Success && index < OldFiles + NumFilesToAdd;
index++)
{
(*ArrayPtr)[index] = malloc(InitWidth);
if((*ArrayPtr)[index] != NULL)
{
(*ArrayPtr)[index][0] = '\0';
}
else
{
Success = 0;
}
}
}
else
{
Success = 0;
}
return Success;
}

int ConsolidateStrArray(char **ArrayPtr,
size_t NumFiles)
{
size_t index;
size_t Len;
int NumFailures = 0;

for(index = 0; index < NumFiles; index++)
{
/* If the library has been correctly used, no
* index pointer will ever be NULL, so we should
* assert that this is the case.
*/
assert(ArrayPtr[index] != NULL);
Len = 1 + strlen(ArrayPtr[index]);
if(0 == ResizeOneString(ArrayPtr, index, Len))
{
++NumFailures;
}
}
return NumFailures;
}

/* end of strarr.c */
/*
gcc -Wall -Wextra -c -o string2.o strarr2.c */

end source listings

From: Moi on
On Wed, 27 Jan 2010 00:21:30 -0700, frank wrote:

> Hello again comp.unix.programer,gnu.gcc.help
>
> I would like to develop a small C utility that does something that a
> mortensen child can use. If I don't get it done before the end of
> january, then it's not a x-mas gift. I bought _Crossing the Threshold
> of Hope_ for Alan and have a thumbdrive of music for Robyn.
>
> So this is to make a source listing and not much else. I'll do that
> after the sig so you won't have to read it unless you want to.
>
> What follows is the readdir() I understand best and then working code
> from unleashed that has a 2-d resizable array.
>
> Jens Thoerring has given me the best design idea that I have right now,
> but if you think you have a better one given the source below, then I'm
> all ears.
>
> Thanks for your constructive comment and cheers,

A few points:
0) you need to include a few headers. The code as you posted it did not even compile.
1) I don't understand your use of readdir_r(). readdir() seems good enough, IMO.
2) IIRC Jens Thoerring said something about your choice of "API" / and use of return value.
It is crucial if you design a function that "returns" a collection (list) of
things, that you make choices of how and what to return.
3) I did not look at the string-stuff it is too messy for me, and I think you could
put what you need into less lines. Also: you realloc to often, causing a 1/2(N*N)
amount of "memory operations".
4) I compacted your process_directory() function for you.

**************************/

#define MOI 1
#if MOI
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#endif

#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>

#define PATH_SIZE 300


#if MOI
unsigned
process_directory (char *theDir)
{
DIR *dir = NULL;
struct dirent entry;
struct dirent *entryPtr = NULL;
int retval = 0;
unsigned count = 0;
char pathName[PATH_SIZE + 1];
size_t dirlen, namelen;

/* Open the given directory, if we can. */
dir = opendir (theDir);
if (dir == NULL) {
fprintf (stderr, "Error opening %s: %s\n", theDir, strerror (errno));
return 0;
}

dirlen = strlen(theDir);
for( retval = readdir_r (dir, &entry, &entryPtr); entryPtr != NULL; retval = readdir_r (dir, &entry, &entryPtr)) {
struct stat entryInfo;

if (!strcmp (entry.d_name, ".") || !strcmp (entry.d_name, "..") ) continue;
namelen = strlen(entry.d_name);

if (dirlen+1+namelen+1 >= sizeof pathName) {
fprintf(stderr,"Name too long: %u+1+%u+1 %s/%s\n"
, (unsigned) dirlen, (unsigned) namelen,theDir,entry.d_name );
continue; }
memcpy (pathName, theDir, dirlen);
pathName[dirlen] = '/';
memcpy (pathName+dirlen+1, entry.d_name, namelen +1);

if (lstat (pathName, &entryInfo) == -1) { /* stat() failed, let's party */
fprintf (stderr, "Error statting %s: %s\n", pathName, strerror (errno)); continue; }

count++;
if (S_ISDIR (entryInfo.st_mode)) { /* directory */
printf ("processing %s/\n", pathName);
count += process_directory (pathName);
continue; }
if (S_ISREG (entryInfo.st_mode)) { /* regular file */
printf ("\t%s has %lld bytes\n"
, pathName, (long long) entryInfo.st_size);
continue; }
if (S_ISLNK (entryInfo.st_mode)) { /* symbolic link */
char targetName[PATH_SIZE + 1];
if (readlink (pathName, targetName, PATH_SIZE) == -1) {
printf ("\t%s -> (invalid symbolic link!)\n", pathName);
continue; }
printf ("\t%s -> %s\n", pathName, targetName);
continue; }
printf ("\t%s (Strange Mode: 0x%x)\n", pathName, entryInfo.st_mode);
}

/* Close the directory and return the number of entries. */
(void) closedir (dir);
return count;
}

/***************
HTH,
AvK
From: John Gordon on
In <7sa7rrFg81U1(a)mid.individual.net> frank <frank(a)example.invalid> writes:

> Jens Thoerring has given me the best design idea that I have right now,
> but if you think you have a better one given the source below, then I'm
> all ears.

If you really want help it's best to give a short description of what the
code is intended to do and perhaps mention some specific ways you'd like
to see the code improve, rather than just dumping the code and asking us
to "make it better."

--
John Gordon A is for Amy, who fell down the stairs
gordon(a)panix.com B is for Basil, assaulted by bears
-- Edward Gorey, "The Gashlycrumb Tinies"

From: Ben Bacarisse on
frank <frank(a)example.invalid> writes:
> Hello again comp.unix.programer,gnu.gcc.help

I can't see the relevance to gnu.gcc.help so I've removed that NG.

> I would like to develop a small C utility that does something that a
> mortensen child can use. If I don't get it done before the end of
> january, then it's not a x-mas gift.

You've pre-decided that this is a C learning exercise which is not
obviously a goal that is compatible with getting something working in
a few days time.

I don't know what you intend (a short description of the purpose would
help) but the code you posted is equivalent to a few lines of bash
script (or Perl or Python...). If you don't know any of these,
learning enough bash to do what the C code does would not take long (a
day or so).

<snip>
--
Ben.
From: Andrew Poelstra on
On 2010-01-27, Moi <root(a)invalid.address.org> wrote:
> On Wed, 27 Jan 2010 00:21:30 -0700, frank wrote:
>
>> Hello again comp.unix.programer,gnu.gcc.help
>>
>> I would like to develop a small C utility that does something that a
>> mortensen child can use. If I don't get it done before the end of
>> january, then it's not a x-mas gift. I bought _Crossing the Threshold
>> of Hope_ for Alan and have a thumbdrive of music for Robyn.
>>
>> So this is to make a source listing and not much else. I'll do that
>> after the sig so you won't have to read it unless you want to.
>>
>> What follows is the readdir() I understand best and then working code
>> from unleashed that has a 2-d resizable array.
>>
>> Jens Thoerring has given me the best design idea that I have right now,
>> but if you think you have a better one given the source below, then I'm
>> all ears.
>>
>> Thanks for your constructive comment and cheers,
>
> A few points:
> 0) you need to include a few headers. The code as you posted it did not even compile.

I changed
#include "strarr2.h"
to
#include "strarr.h"

and it compiled. I think he just made a typo giving the filename of the
string header.

 |  Next  |  Last
Pages: 1 2 3 4 5 6 7
Prev: Reading /proc/<pid>/maps
Next: Code and Creation 73169