🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.unix.programmer
Article #3423

Re: readir() II

#3423
From: Moi
Date: Sat, 06 Feb 2010 12:58
206 lines
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-mail
References: <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