Help Required!!!!!

This is a discussion on Help Required!!!!! within the C Programming forums, part of the General Programming Boards category; Right, anyone interested in helping, i have a small problem! ...I know that the code isn't that great, it hasn't ...

  1. #1
    Matt Conway bobthebullet990's Avatar
    Join Date
    Nov 2005
    Location
    Cambridge
    Posts
    121

    Help Required!!!!!

    Right, anyone interested in helping, i have a small problem! ...I know that the code isn't that great, it hasn't yet been tuned up, its just in a working state! ...For example the dynamic 2d array will be converted to a malloc memory space!!!! but for the time being all that is ok!!!!

    Right, the problem is if you type:

    Code:
    [root@localhost shell]# ./myls -l
    list of contents for: cwd
    -rwxr-xr-x      1 root     root         15756 Fri Nov 25 13:36:42 2005 myls
    -rw-r--r--      1 root     root         13584 Fri Nov 25 13:36:40 2005 myls.c
    -rw-r--r--      1 root     root          7131 Fri Nov 25 10:15:49 2005 myls.c~
    -rwxr-xr-x      2 root     root          4096 Fri Nov 25 11:31:09 2005 test1
    Which is perfect output, exactly what i want!!!! However, if you type:

    Code:
    [root@localhost shell]# ./myls /tmp -l
    list of contents for: /tmp
    File attributes for mcop-root cannot be found!
    File attributes for orbit-matt cannot be found!
    File attributes for orbit-root cannot be found!
    File attributes for plugtmp cannot be found!
    File attributes for plugtmp-1 cannot be found!
    File attributes for ssh-XX9iLygl cannot be found!
    File attributes for ssh-XXJtVUOu cannot be found!
    File attributes for xmms_root.0 cannot be found!
    ARRGGHHH!!!! Why can it not find the attributes for the names?????


    ...Its not the fact that you have given a directory name to list because:

    Code:
    [root@localhost shell]# ./myls /home
    list of contents for: /home
    matt
    mix.mp3
    shell
    and its not the options because:

    Code:
    [root@localhost shell]# ./myls -a /home -l
    list of contents for: /home
    -rwxr-xr-x      3 root     root          4096 Fri Nov 25 13:36:42 2005 .
    -rwxr-xr-x      4 root     root          4096 Thu Nov 24 17:54:10 2005 ..
    File attributes for matt cannot be found!
    File attributes for mix.mp3 cannot be found!
    File attributes for shell cannot be found!

    I have been boggling my brain for some time now, but just can't work out why!!!! ....Here is my source code.....



    Code:
    /**********************************************************************************************/
    /**                                                                                          **/
    /** FILE               : myls.c                                                              **/
    /** DESCRIPTION        : function to list all the files in the current working directory     **/
    /** SUPPORTED SWITCHES : -l - List all file details                                          **/
    /**                      -a - List all files in directory                                    **/
    /** AUTHOR             : Matt Conway (03500546)                                              **/
    /** DATE               : 15/11/2005                                                          **/
    /**                                                                                          **/
    /**********************************************************************************************/
    
    #include <dirent.h>
    #include <stdio.h>
    #include <string.h>
    #include <sys/param.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <pwd.h>
    #include <grp.h>
    #include <time.h>
    #include <locale.h>
    #include <langinfo.h>
    #include <stdint.h>
    
    /* STATUS FLAGS USED TO DISCOVER SWITCHES USED */
    #define AFLAG   0x01          /* 0x01  1  00000001 - set when -a is used */
    #define LFLAG   AFLAG << 1    /* 0x02  2  00000010 - set when -l is used */
    #define XFLAG   LFLAG << 1    /* 0x04  4  00000100 - set when no switches are used */
    
    /* PROTOTYPES */
    int openDirectory(char theProgram[], char thePath[], int whichSwitches);
    void addDataToArray(int x, int y, DIR *theDir, int whichSwitches);
    int sortCompare(const void *str1, const void *str2);
    
    /* GLOBAL VARIABLES */
    struct dirent *dir;    /* pointer to file structure - that contains all file details */
    
    int main(int argc, char **argv){
    
      /* SET UP VARIABLES */
      int theSwitches;     /* int that contains multiple flags as bits */
      int retVal = 0;      /* return value from other functions if they were called. */
      int i = 0;           /* loop counter */
      char *cwdir = ".";   /* pointer the string pathname for the current working directory location */
      int dirCount = 0;    /* for counting the number of directories user wants listed */
    
      /* Find out which switches the user wishes to use when displaying directory contents */
      while ((retVal = getopt(argc, argv, ":al")) != -1) {
        switch (retVal) {
          case 'a': theSwitches = theSwitches |= AFLAG;  /* set AFLAG bit */
            break;
          case 'l': theSwitches = theSwitches |= LFLAG;  /* set LFLAG bit */
            break;
          case '?': 
            /* inform user that invalid switch was used */
            printf("%s: USEAGE: <directory-name> <switch: -a -l>");     
            break;
        }
      }
      /* NOTE: If this is put into case default, it does not get set!!! */
      if (!(theSwitches & AFLAG) && !(theSwitches & LFLAG)){
        theSwitches = theSwitches |= XFLAG; /* set XFLAG bit */
      }
      
      /* Did the user specify more than one directory to list contents of */
      while (argv[i] != NULL){
        if (i != 0){
          if (strncmp(argv[i], "/", 1) == 0){
            dirCount++;
            retVal = openDirectory(argv[0], argv[i], theSwitches);
            if (retVal != 0)
              printf("%s: Cannot find directory %s, or it does not exist!\n",argv[0],argv[i], theSwitches);
          }
          else if (!strncmp(argv[i], "-", 1) == 0){
            dirCount++;
            retVal = openDirectory(argv[0], argv[i], theSwitches);
            if (retVal != 0)
              printf("%s: Cannot find directory %s, or it does not exist!\n",argv[0],argv[i],theSwitches);
          }
        }
        i++;
      } /* loop */
    
      /* User did not specify a directory location, therefore, list current directory */
      if (dirCount == 0) openDirectory(argv[0], cwdir, theSwitches);
    
      return 0;
    
    } /* main */
    
    
    /**********************************************************************************************/
    /**                                                                                          **/
    /** FUNCTION           : openDirectory                                                       **/
    /** DESCRIPTION        : Function to count the number of files / directories contained       **/
    /**                      within the directory that the user wishes to list, also, counts     **/
    /**                      the number of chars for the longest name                            **/
    /** PARAMETERS         : array containing the program name i.e. argv[0]                      **/
    /**                      array containing the pathname of the directory                      **/
    /**                      whichSwitch - each of the 8 bits is a flag turned on or off to      **/
    /**                                    indicate whether or not a particular switch is used   **/ 
    /** AUTHOR             : Matt Conway (03500546)                                              **/
    /** DATE               : 18/11/2005                                                          **/
    /**                                                                                          **/
    /**********************************************************************************************/
    int openDirectory(char theProgram[], char thePath[], int whichSwitches){
    
      int contentCount = 0;  /* the number of dir(s) / file(s) within the directory to list */
      int maxChars = 0;      /* the number of chars for the longest dir / file name in directory to list */
      DIR *theDirectory;     /* pointer to the directory - used to get all the files within the cwd! */
    
      theDirectory = opendir(thePath);
    
      /* if (whichSwitches & AFLAG) printf("aflag = 1\n"); */
    
      if (theDirectory){
         if (thePath == ".")
           printf("list of contents for: cwd\n");
         else
           printf("list of contents for: %s\n", thePath);
    
         /* count the number of files and directories */
         while ((dir = readdir(theDirectory))){
           if (strncmp(dir->d_name, ".", 1) == 0){
             if (whichSwitches & AFLAG){
               contentCount++;
               /* Check to see if the current name is longer than the longest so far */
               if (strlen(dir->d_name) > maxChars)
                 maxChars = strlen(dir->d_name);
             }
           }
           else{
             contentCount++;
             if (strlen(dir->d_name) > maxChars)
               maxChars = strlen(dir->d_name);
           }
         }
         /* strlen does not count the /0 string termination char, so make extra space for this! */
         maxChars++;
    
         /* rewind theDirectory (currently at EOD) to BOD for listing directory contents */
         rewinddir(theDirectory); 
         
         /* Add directory data to the array */
         addDataToArray(contentCount, maxChars, theDirectory, whichSwitches);
    
         /* make theDirectory point to the first directory entry for listing*/
         closedir(theDirectory);
    
         return 0;
      }
      else 
        return 1;
    
    } /* openDirectory */
    
    
    /**********************************************************************************************/
    /**                                                                                          **/
    /** FUNCTION           : addDataToArray                                                      **/
    /** DESCRIPTION        : Function to create a dynamic 2d array, large enough to store all    **/
    /**                      filenames and directory names that are contained within the         **/
    /**                      directory that is to be listed. It then adds all these names        **/
    /**                      to the array and sorts them into alphabetical order                 **/
    /** PARAMETERS         : x - the length of the array i.e. the number of file / dir names     **/
    /**                      y - the width of the array i.e. the number of chars of the longest  **/
    /**                          file / dir name                                                 **/
    /**                      *theDir - pointer to the directory structure containing the file    **/
    /**                                and dir names                                             **/
    /**                      whichSwitch - each of the 8 bits is a flag turned on or off to      **/
    /**                                    indicate whether or not a particular switch is used   **/ 
    /** AUTHOR             : Matt Conway (03500546)                                              **/
    /** DATE               : 19/11/2005                                                          **/
    /**                                                                                          **/
    /**********************************************************************************************/
    void addDataToArray(int x, int y, DIR *theDir, int whichSwitch){
    
      char theArray[x][y];
      int z = 0;
      struct stat fileattrib;
      struct passwd  *pwd;
      struct group *grp;
      struct tm *tm;
      char datestring[256];
      int fileMode;
    
      while ((dir = readdir(theDir)) != NULL){
        if (strncmp(dir->d_name, "." , 1) == 0){
          /* check to see if user is using option -a */
          if (whichSwitch & AFLAG){
            strcpy(theArray[z], dir->d_name);
            z++;
          }
        }
        else{
          strcpy(theArray[z], dir->d_name);
          z++;
        }
      } /* loop */
    
      qsort((void*)theArray, (size_t)x, y, sortCompare);
    
      /* Print the directory contents */
      for (z = 0; z < x; z++){
        /* Did the user request to print the files with -l option? */
        if (whichSwitch & LFLAG){
          /* Get the directory entries info */
          if (stat(theArray[z], &fileattrib) == 0){
            /* print a leading dash as start of file / directory permissions */
            printf("-");
            fileMode = fileattrib.st_mode;
            /* Check owner permissions */
            if ((fileMode & S_IRUSR) && (fileMode & S_IREAD))
              printf("r");
            else
              printf("-");
            if ((fileMode & S_IWUSR) && (fileMode & S_IWRITE)) 
              printf("w");
            else
              printf("-");
            if ((fileMode & S_IXUSR) && (fileMode & S_IEXEC))
              printf("x");
            else
              printf("-");
            /* Check group permissions */
            if ((fileMode & S_IRGRP) && (fileMode & S_IREAD))
              printf("r");
            else
              printf("-");
            if ((fileMode & S_IWGRP) && (fileMode & S_IWRITE))
              printf("w");
            else
              printf("-");
            if ((fileMode & S_IXGRP) && (fileMode & S_IEXEC))
              printf("x");
            else
              printf("-");
            /* check other user permissions */
            if ((fileMode & S_IROTH) && (fileMode & S_IREAD))
              printf("r");
            else
              printf("-");
            if ((fileMode & S_IWOTH) && (fileMode & S_IWRITE))
              printf("w");
            else
              printf("-");
            if ((fileMode & S_IXOTH) && (fileMode & S_IEXEC))
              /* because this is the last permission, leave 3 blank spaces after print */
              printf("x   ");
            else
              /* because this is the last permission, leave 3 blank spaces after print */
              printf("-   ");
            
            /* print number of links for the file / directory */
            printf("%4d", fileattrib.st_nlink);
            
            /* Print the owners name if it was found using getpwuid, if not, print the numeric code for owner */
            if ((pwd = getpwuid(fileattrib.st_uid)) != NULL)
              printf(" %-8.8s", pwd->pw_name);
            else
              printf(" %-8d", fileattrib.st_uid);
            
            /* Print the group name if it was found using getgrgid, if not, print the numeric code for owner */
            if ((grp = getgrgid(fileattrib.st_gid)) != NULL)
              printf(" %-8.8s", grp->gr_name);
            else
              printf(" %-8d", fileattrib.st_gid);
            
            /* Print file size */
            printf(" %9jd", (intmax_t)fileattrib.st_size);
            
            /* Print the date / time when the file was last updated */    
            tm = localtime(&fileattrib.st_mtime);
            /* Get localized date string. */
            strftime(datestring, sizeof(datestring), nl_langinfo(D_T_FMT), tm);
            printf(" %s %s\n", datestring, theArray[z]);
          }
          else 
            printf("File attributes for %s cannot be found!\n",theArray[z]);
        }
        /* No -l switch being used, so just print the directory entry name */
        else
          printf("%s\n",theArray[z]);
      
      } /* loop */
    
    } /* addDataToArray */
    
    
    /**********************************************************************************************/
    /**                                                                                          **/
    /** FUNCTION           : sortCompare                                                         **/
    /** DESCRIPTION        : function to compare 2 strings and returns an integer less than,     **/
    /**                      equal to, or greater than zero if str1 is found, respectively, to   **/
    /**                      be less than, to mathc, or be greater than str2.                    **/
    /** PARAMETERS         : a pointer to the first string to be compared                        **/
    /**                      a pointer to the second string to be compared                       **/
    /** AUTHOR             : Matt Conway (03500546)                                              **/
    /** DATE               : 21/11/2005                                                          **/
    /**                                                                                          **/
    /**********************************************************************************************/
    int sortCompare(const void *str1, const void *str2){
      return strcmp(str1,str2);   
    }

    Anyone that has any ideas! you are ledgends!!! Thanks a bunch guys for looking at my code!!!!

  2. #2
    ZuK
    ZuK is offline
    Registered User
    Join Date
    Aug 2005
    Location
    Austria
    Posts
    1,990
    Quote Originally Posted by stat man-page
    These functions return information about the specified file. You do not need any access rights to the file to get this information but you need search rights to all directories named in the path leading to the file.
    Have a look what happens if you run your program as root or examine errno after stat fails.
    Kurt

  3. #3
    Matt Conway bobthebullet990's Avatar
    Join Date
    Nov 2005
    Location
    Cambridge
    Posts
    121
    Thanks for the help kurt, but if you look carefully enough, you will have seen that the program was being run by user root...

    Code:
    [root@localhost shell]
    But thanks anyway!!!!

    ....I think the problem is that when using -l switch, the program is trying to access the files / directories that are situated in the current working directory, which explains why when you use -al, you can see the attributes for . and .. but not for any of the other files as they don't exist in the current working directory, but the files . and .. do!

    However, how do i overcome this problem??? Any ideas?

  4. #4
    and the hat of wrongness Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    32,442
    Perhaps you should work on the warnings first

    Code:
    $ gcc -W -Wall -g foo.c
    foo.c: In function ‘main’:
    foo.c:52: warning: operation on ‘theSwitches’ may be undefined
    foo.c:54: warning: operation on ‘theSwitches’ may be undefined
    foo.c:58: warning: too few arguments for format
    foo.c:64: warning: operation on ‘theSwitches’ may be undefined
    foo.c:74: warning: too many arguments for format
    foo.c:80: warning: too many arguments for format
    foo.c: In function ‘openDirectory’:
    foo.c:130: warning: comparison between signed and unsigned
    foo.c:136: warning: comparison between signed and unsigned
    foo.c: At top level:
    foo.c:108: warning: unused parameter ‘theProgram’

  5. #5
    Matt Conway bobthebullet990's Avatar
    Join Date
    Nov 2005
    Location
    Cambridge
    Posts
    121
    OK!!!! ...Done that, but any suggestions as to how to set the switches??? ...I can't see anything wrong with setting them like this! ...I have looked at many examples and they do it the same way! ...What would you suggest to get rid of the warnings??? Cheers!

    Code:
    cd /home/shell/
    gcc -W -Wall -o myls myls.c
    myls.c: In function `main':
    myls.c:52: warning: operation on `theSwitches' may be undefined
    myls.c:54: warning: operation on `theSwitches' may be undefined
    myls.c:64: warning: operation on `theSwitches' may be undefined
    
    Compilation finished at Fri Nov 25 15:08:40

  6. #6
    and the hat of wrongness Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    32,442
    You could start with
    int theSwitches = 0;

  7. #7
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,046
    It's saying it "may be undefined" because you're doing something like this:
    Code:
    int x;
    if(!x) {}  /* x has not been assigned a value . . . */
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  8. #8
    ZuK
    ZuK is offline
    Registered User
    Join Date
    Aug 2005
    Location
    Austria
    Posts
    1,990
    Code:
    theSwitches = theSwitches |= AFLAG;  /* set AFLAG bit */
    Isn't that redundant ? 2 assignements to the same variable in one statenent

    Code:
    theSwitches |= AFLAG;  /* set AFLAG bit */
    should be enough
    Kurt

  9. #9
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,046
    And you might want to save strlen()'s return value so you don't have to call it twice.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  10. #10
    Matt Conway bobthebullet990's Avatar
    Join Date
    Nov 2005
    Location
    Cambridge
    Posts
    121
    Awesomeo!!! thanks kurt!!! ...I did use that to begin with, but it wasn't setting the bits correct, but i have changed the code to pass the int containing the flags as a parameter between functions rather than keep it as a very bad and horrible global variable!!!!!

  11. #11
    Matt Conway bobthebullet990's Avatar
    Join Date
    Nov 2005
    Location
    Cambridge
    Posts
    121
    Quote Originally Posted by dwks
    And you might want to save strlen()'s return value so you don't have to call it twice.
    ...I don't really understand what you mean by this! ...I call strlen twice because if the user is using the -a switch, they wish to display all files & directories, therefore, if the file/dir name starts with a leading . the program must display it, if the user is not using switch -a, the program ignores these files/dirs!

    Therefore, in the case that the user wishes to display all files/dirs, the program must find the length of the longest filename including the file/dirs that begin with a leading zero! If the user does not wish to list all files/dirs in the directory, the program ignores any file with a leading . therefore, eliminating the need to count the length of that file/dir, as it will not be displayed by the program!!!!

    An example, the directory test contains the following files:

    Code:
    test.c
    test.txt
    .elephant.txt
    tiger.jpg
    Now, if you wish to display the contents of this directory, say using the ls command with no switches, the output will be:

    Code:
    test.c
    test.txt
    tiger.jpg
    However, if you wish to display all files in this directory using ls -a, the output will be:

    Code:
    .
    ..
    test.c
    test.txt
    tiger.jpg
    .elephant.txt
    Now, if the user is not requesting to use the switch -a, it means that the program will not display the file .elephant.txt (which also happens to have the longest name out of all files/dirs contained in the directory) Therefore, the program does not need to count the number of chars in this string, if it did, the array that contains file/dir names would be unecessarily bigger than the largest filename within it...

    the array would look like:

    Code:
      theArray[6][14]   /*allow for the \0 char as strlen doesn't count this! */
      
      /*but would only contain elements: */
      theArray[0] = "test.c";
      theArray[1] = "test.txt";
      theArray[2] = "tiger.jpg";
      theArray[3] = NULL;
      theArray[4] = NULL;
      theArray[5] = NULL;
    
      /* As you can see from the above, the array contains plenty of free-space, which is super inefficient!!! */
    Hopefully, now, you can see why strlen is used twice!!!!!!

  12. #12
    ZuK
    ZuK is offline
    Registered User
    Join Date
    Aug 2005
    Location
    Austria
    Posts
    1,990
    This would still be a lot more efficient
    Code:
         while ((dir = readdir(theDirectory))){
           int dirlen=strlen(dir->d_name);
           if (strncmp(dir->d_name, ".", 1) == 0){
             if (whichSwitches & AFLAG){
               contentCount++;
               /* Check to see if the current name is longer than the longest so far */
               if (dirlen > maxChars)
                 maxChars = dirlen;
             }
           }
           else{
             contentCount++;
             if (dirlen > maxChars)
               maxChars = dirlen;
           }
         }
    Kurt

  13. #13
    Matt Conway bobthebullet990's Avatar
    Join Date
    Nov 2005
    Location
    Cambridge
    Posts
    121
    The code is tidier, but i am not sure if it is any more efficient??? ...as strlen will still only be called once for every loop! ...I think i will use your idea though because the layout is a lot easier to follow!!!! Thanks a lot buddy!!!!!

  14. #14
    ZuK
    ZuK is offline
    Registered User
    Join Date
    Aug 2005
    Location
    Austria
    Posts
    1,990
    As dwks already said it's called twice
    Code:
               if (strlen(dir->d_name) > maxChars) // first time
                 maxChars = strlen(dir->d_name);   // second time
    Kurt

  15. #15
    Matt Conway bobthebullet990's Avatar
    Join Date
    Nov 2005
    Location
    Cambridge
    Posts
    121
    DONE IT!!!!!

    Was being a bit silly here!!!! ...I realised that i wasn't actually changing to the directory that i wanted to list when calling stat(), therefore, I have now added a new parameter to the addDataToArray function which is the path of where the directory is who's contents require displaying!

    So now it changes to the directory to list files from and then stats the files, displaying full file attributes for each file!!!!!!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Problem building Quake source
    By Silvercord in forum Game Programming
    Replies: 16
    Last Post: 07-11-2010, 09:13 AM
  2. Lvalue required error
    By eklavya8 in forum C Programming
    Replies: 5
    Last Post: 01-03-2009, 03:47 PM
  3. Replies: 28
    Last Post: 07-16-2006, 11:35 PM
  4. NAQ: Everything you never wanted to know about CPP
    By evildave in forum C Programming
    Replies: 21
    Last Post: 12-12-2005, 09:56 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21