Article View: comp.unix.programmer
Article #3423Re: readir() II
From: Moi
Date: Sat, 06 Feb 2010 12:58
Date: Sat, 06 Feb 2010 12:58
206 lines
7008 bytes
7008 bytes
On Wed, 27 Jan 2010 00:21:30 -0700, frank wrote:
> Hello again comp.unix.programer,gnu.gcc.help
>
> 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.
Ok, I cleaned it up a bit, removing the need for multidimentional arrays
and ***pointers. (it does use the struct hack, but that is still allowed in c89/c90 ;-)
Sorry for the mixed indentation ...
*****************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
char * strdup ( const char *org ); /* sorry! */
ssize_t readlink(const char *path, char *buf, size_t bufsiz); /* sorry */
#define MOI AvK
#define SHOW_BAGS 0
#define SHOW_PROGRESS 0
#define PATH_SIZE 4096
struct bag {
unsigned used;
unsigned size;
char *data[1]; /* struct hack here ... */
};
struct bag * bag_add( struct bag * bag, char *str );
char * bag_del( struct bag * bag );
struct bag * bag_resize( struct bag * old, unsigned size );
struct bag * get_files( struct bag *dirs );
/* NB: this program does about the same as "find arg[1]... arg[n] -type f"
* (except for some details, such as ordering and the handling of symlinks)
*/
int main( int argc, char *argv[] )
{
struct bag *todo=NULL, *result=NULL;
unsigned iter;
while( argc-- > 1 ) {
#if SHOW_PROGRESS
fprintf( stderr, "Add to todo list[%d]: %s\n", argc, argv[argc] );
#endif
todo = bag_add ( todo, strdup( argv[argc] ) );
}
result = get_files ( todo );
if ( result ) for ( iter = 0; iter < result->used; iter++ ) {
fprintf( stdout, "[%u]: %s\n", iter, result->data[iter] );
}
return 0;
}
struct bag * get_files( struct bag *dirs )
{
DIR *dir = NULL;
struct dirent *dp = NULL;
char *dirname, *fullpath ;
size_t dirlen, namelen;
struct bag *files = NULL;
int rc;
for ( ; dirname = bag_del(dirs) ; free(dirname) ) {
/* Open the given directory, if we can. */
#if SHOW_PROGRESS
fprintf ( stderr, "Processing %s\n", dirname );
#endif
dir = opendir ( dirname );
if ( !dir ) {
fprintf ( stderr, "Error opening %s: %d(%s)\n", dirname, errno, strerror (errno));
continue;
}
dirlen = strlen( dirname );
while ( dp = readdir(dir )) {
struct stat sst;
if ( !strcmp ( dp->d_name, "." ) || !strcmp ( dp->d_name, ".." ) ) continue;
namelen = strlen( dp->d_name );
fullpath = malloc( dirlen + 1 + namelen +1 );
if ( !fullpath ) {
fprintf( stderr,"Name too long: %u+1+%u+1 %s/%s\n"
, (unsigned) dirlen, (unsigned) namelen, dirname, dp->d_name );
continue; }
memcpy ( fullpath, dirname, dirlen );
fullpath[dirlen] = '/';
memcpy ( fullpath+dirlen+1, dp->d_name, namelen +1 );
if ( lstat ( fullpath, &sst ) == -1 ) { /* stat() failed, let's party */
fprintf ( stderr, "Error statting %s: %s\n", fullpath, strerror (errno)); continue; }
if ( S_ISDIR ( sst.st_mode )) { /* directory */
#if SHOW_PROGRESS
fprintf ( stderr, "\tAdding Dir %s:/\n", fullpath );
#endif
dirs = bag_add( dirs, fullpath );
continue; }
if ( S_ISREG ( sst.st_mode )) { /* regular file */
#if SHOW_PROGRESS
fprintf ( stderr, "\t%s has %lld bytes\n"
, fullpath, (long long) sst.st_size );
#endif
files = bag_add( files, fullpath );
continue; }
if ( S_ISLNK ( sst.st_mode )) { /* symbolic link */
char targetName[PATH_SIZE + 1];
if ( readlink ( fullpath, targetName, PATH_SIZE ) == -1) {
fprintf ( stderr, "\t%s -> (invalid symbolic link!)\n", fullpath );
goto skip; }
#if SHOW_PROGRESS
strcpy( targetName+PATH_SIZE-3, "/.." );
fprintf ( stderr, "\t%s -> %s\n", fullpath, targetName);
#endif
goto skip; }
fprintf ( stderr, "\t%s :Strange Mode: 0x%x\n", fullpath, sst.st_mode);
skip:
free( fullpath);
}
rc = closedir ( dir );
if (rc == -1) fprintf ( stderr, "Error closdir(%s): %s", dirname, strerror (errno));
}
return files;
}
/***************/
struct bag * bag_add( struct bag * bag, char *str )
{
#if SHOW_BAGS
fprintf( stderr, "Bag_add(%u+%s)\n", bag?bag->used:0, str );
#endif
if ( !bag || !bag->size ) bag = bag_resize( bag, 2 );
else if ( bag->used > bag->size ) bag = bag_resize( bag, 2 * bag->size );
if ( !bag || bag->used > bag->size ) {
fprintf( stderr, "The bag got robbed.\n" );
return bag;
}
bag->data[bag->used++] = str;
return bag;
}
char * bag_del( struct bag * bag )
{
#if SHOW_BAGS
fprintf( stderr, "Bag_del(%u --> %s )\n"
, bag?bag->used:0
, bag && bag->used ? bag->data[bag->used-1] : "NoNe" );
#endif
if ( !bag || !bag->used ) return NULL;
return bag->data[--bag->used] ;
}
struct bag * bag_resize( struct bag * old, unsigned size )
{
struct bag * new;
unsigned used;
#if SHOW_BAGS
fprintf( stderr, "Bag_resize(%u -->> %u)\n", old?old->size:0, size );
#endif
if ( !size ) { free ( old ); return NULL; }new = malloc ( sizeof *new + size * sizeof new->data[0] );
if ( !new ) {
fprintf( stderr, "Bag_resize: Malloc(%u) went wrong\n"
, (unsigned) sizeof *new + size * sizeof new->data[0] );
return old;
}
used = old ? size < old->used ? size : old->used : 0;
if ( used ) memcpy ( new->data, old->data, used * sizeof new->data[0] );
new->used = used;
new->size = size;
for ( ; used < size; used++ ) new->data[used] = NULL;
free ( old );
return new;
}
/*****
HTH,
AvK
Technical Details
Message-ID:
<6d5a$4b6d6760$5350c024$11295@cache110.multikabel.net>Path:
arc1-ca.pugleaf.net!g2news1.google.com!news4.google.com!feeder.news-service.com!feed.xsnews.nl!border-1.ams.xsnews.nl!tudelft.nl!txtfeed1.tudelft.nl!multikabel.net!newsfeed10.multikabel.net!post30.multikabel.net!cache110.multikabel.net!not-for-mailReferences:
<7sa7rrFg81U1@mid.individual.net>Show Full Headers
Complete Article Headers
X-Google-Thread: 1200bcf240,1d887f475f1c894c X-Google-Attributes: gid1200bcf240,public,usenet X-Google-NewGroupId: yes X-Google-Language: ENGLISH,ASCII-7-bit Path: arc1-ca.pugleaf.net!g2news1.google.com!news4.google.com!feeder.news-service.com!feed.xsnews.nl!border-1.ams.xsnews.nl!tudelft.nl!txtfeed1.tudelft.nl!multikabel.net!newsfeed10.multikabel.net!post30.multikabel.net!cache110.multikabel.net!not-for-mail From: Moi <root@invalid.address.org> Subject: Re: readir() II Newsgroups: comp.unix.programmer,gnu.gcc.help References: <7sa7rrFg81U1@mid.individual.net> User-Agent: Pan/0.132 (Waxed in Black) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Message-ID: <6d5a$4b6d6760$5350c024$11295@cache110.multikabel.net> X-Complaints-To: abuse.cas.news@prolocation.net Organization: Multikabel Date: Sat, 06 Feb 2010 13:58:08 +0100 Lines: 207 NNTP-Posting-Host: 83.80.192.36 (83.80.192.36) NNTP-Posting-Date: Sat, 06 Feb 2010 13:58:08 +0100 X-Trace: 06d5a4b6d6760f6f5658111295