Thread: Program to match filenames and print stat

  1. #1
    Registered User
    Join Date
    May 2010
    Posts
    4

    Program to match filenames and print stat

    I'm writing a program that matches a pattern for filenames in my working directory and prints time information next to the file name. The program is printing a lot of garbage however. I am using an array to collect the filenames and then pass them. Here is the code...



    Code:
           #include <stdio.h>           /* For printf, fprintf */
    #include <string.h>          /* For strcmp */
    #include <ctype.h>           /* For isdigit */
    #include <fcntl.h>           /* For O_RDONLY */
    #include <dirent.h>      /* For getdents */
    #include <sys/stat.h>        /* For IS macros */
    #include <sys/types.h>       /* For modet */
    #include <time.h>            /* For localtime, asctime */
    
    
    /* #define Statements */
    #define MAX_FILES            100
    #define MAX_FILENAME         50
    #define NOT_FOUND            -1
    #define FOREVER              -1
    #define DEFAULT_DELAY_TIME   10
    #define DEFAULT_LOOP_COUNT   FOREVER
    
    
    /* Booleans */
    enum { FALSE, TRUE };
    
    
    /* Status structure, one per file. */
    struct statStruct
     {
       char fileName [MAX_FILENAME]; /* File name */
       int lastCycle, thisCycle; /* To detect changes */
       struct stat status; /* Information from stat () */
     };
    
    
    /* Globals */
    char* fileNames [MAX_FILES]; /* One per file on command line */
    int fileCount; /* Count of files on command line */
    struct statStruct stats [MAX_FILES]; /* One per matching file */
    int loopCount = DEFAULT_LOOP_COUNT; /* Number of times to loop */
    int delayTime = DEFAULT_DELAY_TIME; /* Seconds between loops */
    
    /****************************************************************/
    
    main (int argc,char* argv[])
    {
     parseCommandLine (argc, argv); /* Parse command line */
     monitorLoop (); /* Execute main monitor loop */
     return (/* EXIT_SUCCESS */ 0);
    }
    
    /****************************************************************/
    
    parseCommandLine (int argc,char* argv[])
    /* Parse command line arguments */
    
    {
     DIR *dp;
     struct dirent *dirEntry;
     char fileName [MAX_FILENAME];
     fileCount = 0;
     int i;
     dp = opendir ("/home/c33212");
     if (dp == NULL) fatalError();
    
      while (dirEntry=readdir(dp)) /* Read all directory entries */
        {
                    if((fnmatch("*c", dirEntry->d_name,0)) == 0)
    
           fileNames[fileCount++] = dirEntry->d_name ;
       }
            closedir(dp);
     if (fileCount == 0) usageError ();
    }
    
    /****************************************************************/
    
    
    usageError ()
    
    {
      fprintf (stderr, "Usage: myls <Search-Pattern>");
      exit (/* EXIT_FAILURE */ 1);
    }
    
    /****************************************************************/
    
    monitorLoop ()
    
    /* The main monitor loop */
    
    {
          monitorFiles (); /* Scan all files */
          fflush (stdout); /* Flush standard output */
          fflush (stderr); /* Flush standard error */
    }
    
    /****************************************************************/
    
    monitorFiles ()
    
    /* Process all files */
    
    {
      int i;
    
      for (i = 0; i < fileCount; i++)
        monitorFile (fileNames[i]);
    
    }
    
    /****************************************************************/
    
    monitorFile (char* fileName)
    /* Process a single file/directory*/
    
    {
      struct stat statBuf;
      mode_t mode;
      int result;
    
      result = stat (fileName, &statBuf); /* Obtain file status */
    
    
      mode = statBuf.st_mode; /* Mode of file */
    
      if(S_ISDIR (mode)) /* Directory */
        printf("D%s", fileName);
      else if (S_ISREG (mode) || S_ISCHR (mode) || S_ISBLK (mode))
        updateStat (fileName, &statBuf); /* Regular file */
    }
    
    /****************************************************************/
    
    
    updateStat (char* fileName,struct stat* statBuf)
    /* Add a status entry if necessary */
    
    {
    
    
         addEntry (fileName, statBuf); /* Add new entry */
    
    }
    
    /****************************************************************/
    
    
    addEntry (char* fileName,struct stat* statBuf)
    
    /* Add a new entry into the status array */
    
    {
      int index;
    
      index = nextFree (); /* Find the next free entry */
      if (index == NOT_FOUND) return (NOT_FOUND); /* None left */
      strcpy (stats[index].fileName, fileName); /* Add filename */
      stats[index].status = *statBuf; /* Add status information */
      printEntry (index); /* Display status information */
      return (index);
    }
    
    /****************************************************************/
    
    nextFree ()
    
    /* Return the nextfree index in the status array */
    
    {
      int i;
    
      for (i = 0; i < MAX_FILES; i++)
         return (i);
    
    }
    
    /****************************************************************/
    
    
    printEntry (int index)
    /* Display an entry of the status array */
    
    {
      printf ("%s", stats[index].fileName);
      printStat (&stats[index].status);
    }
    
    /****************************************************************/
    
    printStat (struct stat* statBuf)
    /* Display a status buffer */
    
    {
      printf ("\t\t\t %s",
               asctime (localtime (&statBuf->st_mtime)));
    }
    
    /****************************************************************/
    
    fatalError ()
    
    {
      perror ("monitor: ");
      exit (/* EXIT_FAILURE */ 1);
    }

  2. #2
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    You are using an array of pointers. Unless this is performing a strdup for you, you never actually allocate any space to store your file names:
    Code:
     while (dirEntry=readdir(dp)) /* Read all directory entries */
        {
                    if((fnmatch("*c", dirEntry->d_name,0)) == 0)
    
           fileNames[fileCount++] = dirEntry->d_name ;
    So unless fnmatch happens to malloc up a bunch of memory, and then copies dirEntry->d_name in it, you aren't actually keeping tabs on any file names. (Which is likely why you're getting "a bunch of garbage".)


    Quzah.
    Hope is the first step on the road to disappointment.

  3. #3
    Registered User
    Join Date
    May 2010
    Posts
    4
    Oh ok... Interesting.. Anybody have any tips on how to do that?

  4. #4
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    As opposed to having no memory, I recommend getting some memory for your variable!

    Since a directory could have a lot of files, can you use one char array of say 150 bytes, to hold your file names, and process them one at a time, and then get the next file name?

    Otherwise, you have a choice of making the char array static, or dynamic with malloc(). Having the first dimension of the 2D array, as a pointer, will save a lot of space, imo.

  5. #5
    Registered User
    Join Date
    May 2010
    Posts
    4
    Hmmm.. That sounds like a good solution.. It would probably be better if I dit dynamically though. However, I'm a rookie programmer so I'm struggling with the code.

  6. #6
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by chrisfrmatl View Post
    Hmmm.. That sounds like a good solution.. It would probably be better if I dit dynamically though.
    It is important and inevitable that you will learn to work with dynamic memory.

    HOWEVER, with chunks of less than 1k* it's hard to see how this provides an advantage performance wise -- in fact, it almost certainly would be the opposite, because in almost all contexts the amount of processor activity (read: malloc calls) required to dynamically manage that memory (saving what?) will be far more significant.

    So in real life you would probably just use a statically sized buffer (as Adak says) big enough to deal, and perhaps a mechanism to prevent overflows.

    But again: it is important and inevitable that you will learn to work with dynamic memory.

    * probably more like 4K
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  7. #7
    Registered User
    Join Date
    May 2010
    Posts
    4
    Hmmmm.. I' made some improvements to the code and I get some filenames to print and other won't.. If anybody would like to run it on their system, I can give you the code.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. My program, anyhelp
    By @licomb in forum C Programming
    Replies: 14
    Last Post: 08-14-2001, 10:04 PM