On Mon, 11 Jun 2001, Shawn wrote:

> I want an inline C subroutine in my perl program to:
>   1) opendir a directory if readable
>   2) readdir the dir
>   3) step through all the files and lstat them
>   4) return the stat data of all the files (in whatever form is most
>      convenient, probably SV)

I guess the most convenient would be to return nothing at all.  I've
attached a script that will lstat and push filenames back to perl using
Inline_Stack.  Leaving as much info in C space as possible will speed up
your loop.  Passing all those arrays back to perl is probably a lot of
overhead for large directories.  Be sure to post your results of your
experiment.  I think others will be intersted in this idea of taking tight
loops in perl and Inlining them.  Inline is the perfect tool for this
cause you can just replace the perl loop with C code within the same file.

Ryan Sadler

> Here is why... When I do this in perl, it goes something like:
>   my @stats;
>   opendir DIR, $directory;
>   for (readdir DIR) {
>     my $file = "$directory/$_";
>     @stats = lstat($file);
>   }
>   closedir(DIR);
>
> As you can see, on line 5 I do an lstat with each iteration of the PERL
> loop. I really want to see if extra overhead of doing it from the
> indirection of being inside a PERL loop costs me. I think it does
> because some of the timings I've done for PERL loops vs ls -F on huge
> dirs seem to suggest it.
>
> --
> Hob Goblin
> [EMAIL PROTECTED]
>
> I put my air conditioner in backwards.  It got cold outside.
> The weatherman on TV was confused.  "It was supposed to be hot
> today."
>                                               -- Stephen Wright
>
use Inline C => Config => CCFLAGS => '-Wall';

use Inline C;

map +{ print "$_\n" } , list_dir("/");

__END__
__C__
  
#include <dirent.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"

#define errorMsg printf
#define follow_links 0

struct dnode {                          /* the basic node */
    char *name;                         /* the dir entry name */
    char *fullname;                     /* the dir entry name */
    struct stat dstat;          /* the file stat info */
    struct dnode *next;         /* point at the next node */
};

typedef struct dnode dnode_t;

/* This code was mostly copied from busybox-0.47, GPL applies */
void list_dir( char *path) {
  struct dnode node;
  struct dirent *entry;
  DIR *dir;
  char *fnend, fullname[BUFSIZ+1] ;
  Inline_Stack_Vars;


  if (path==NULL) return;//(NULL);
  strcpy(fullname, path);
  fnend = fullname + strlen(fullname);
  if (fnend[-1] != '/') {
    strcat(fullname, "/");
    fnend++;
  }
  
  dir = opendir(fullname);
  if (dir == NULL) {
    errorMsg("%s: %s\n", fullname, strerror(errno));
    Inline_Stack_Done;
    return;
  }

  Inline_Stack_Reset;
  while ((entry = readdir(dir)) != NULL) {
    /* are we going to list the file- it may be . or .. or a hidden */
    strcpy(fnend, entry->d_name);
    if (follow_links == TRUE) {
      if (stat(fullname, &node.dstat)) {
        errorMsg("%s: %s\n", fullname, strerror(errno));
        continue;
      }
    } else

      if (lstat(fullname, &node.dstat)) {   /* get file stat info into */
        errorMsg("%s: %s\n", fullname, strerror(errno));
        continue;
      }
    Inline_Stack_Push(newSVpv(fullname,0));
  }
  closedir(dir);
  Inline_Stack_Done;
}

Reply via email to