Traversing File Directory Trying to Count Lines in Files With a Specific Extension in C

Viewed 44

I am trying to traverse a filesystem tree. When I come across a file with a certain extension I want to open the file and then count the lines in the file. It seems I am getting a segmentation fault I believe it is after/when I open the file and try to count the lines. Any help on why this is seg faulting would be appreciated.

EDIT: I have deleted the old code because I fixed the seg fault. Now I changed the data to be fed in at the command line. But it seems either the files are not getting opened or it is not counting the lines correctly because when I run it the program will always return 0 lines.

Here is the updated code:

#include <unistd.h>
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>

const char *get_filename_ext(const char *filename) {
    const char *dot = strrchr(filename, '.');
    if(!dot || dot == filename) return "";
    return dot + 1;
}

int printdir(char *dir, char *targetFileExt, int depth)
{
    DIR *dp;
    struct dirent *entry;
    struct stat statbuf;
      int spaces = depth*4;
    int totalLines=0;

    if((dp = opendir(dir)) == NULL) {
        fprintf(stderr,"cannot open directory: %s\n", dir);
        return -1;
    }
    chdir(dir);
    while((entry = readdir(dp)) != NULL) {
        lstat(entry->d_name,&statbuf);
        if(S_ISDIR(statbuf.st_mode)) {
            /* Found a directory, but ignore . and .. */
            if(strcmp(".",entry->d_name) == 0 || strcmp("..",entry->d_name) == 0){
                continue;
            }
            printf("%*s%s/\n",spaces,"",entry->d_name);
            /* Recurse at a new indent level */
            totalLines = printdir(entry->d_name, targetFileExt, depth+1);
        }
        else {
          printf("%*s%s\n",spaces,"",entry->d_name);

          char *currentFileExt = get_filename_ext(entry->d_name);

          if(*currentFileExt == *targetFileExt){
            //open the file for reading
            FILE *fPtr = fopen(entry->d_name, "r");

            //traverse the file
            while(!feof(fPtr)){
              //if there is a new line character
              int temp = fgetc(fPtr);
              if(temp=='\n'){
                //add a line to the total amount of lines
                totalLines++;
              }
            }

            //close the file
            fclose(fPtr);
            fPtr=NULL;
          }
        }
    }
    chdir("..");
    closedir(dp);

    return totalLines;
}

int main(int argc, char* argv[])
{
    char *topdir, pwd[2]=".";
    char *ext;
    if (argc < 2 || argc > 3)
        topdir=pwd;
    else if(argc == 2){
      topdir=argv[1];
    }
    else if(argc == 3){
      topdir=argv[1];
      ext=argv[2];
    }

    printf("Directory scan of %s\n",topdir);
    int lines = printdir(topdir, ext, 0);
    printf("You have written %d lines of %s code!\n", lines, ext);

    return 0;
}
1 Answers

First of all, the filename extension check: if(*currentFileExt == *targetFileExt) Will only work for file extensions with a single character. Consider searching for ".com", and you encounter a ".c" file. get_filename_ext() will return a pointer to the first character after the dot. Then you would be comparing 'c' == 'c'. Consider using strcmp() instead, and make sure targetFileExt does not contain the leading dot, as this is how your code is set up as-is.

Second of all, printdir() in its current form does not accumulate the line count from the subdirectories. Consider the scenario:

  • We're searching for .c files.
  • The directory you're searching in contains two subdirectories, A and B, and nothing else.
  • A contains a 10 LOC .c file, and B contains a 20 LOC .c file.

When you run the code:

  1. You call printdir() from main(), let's say your code first encounters A
  2. The function calls itself recursively and returns 10, so totalLines gets assigned a value of 10.
  3. On the next loop iteration the function encounters B.
  4. The function calls itself recursively, returns 20, so totalLines gets assigned a value of 20.
  5. You have lost the 10 lines from the first loop iteration.

In order to fix this, you have three options:

  • Change the function signature to: int printdir(char *dir, char *targetFileExt, int depth, int totalLines); and remove int totalLines=0;. In the function call it like: totalLines = printdir(entry->d_name, targetFileExt, depth+1, totalLines); Call it from main() passing 0 for totalLines.

  • Change to function signature to accept a pointer to a line count variable, and increment it when you encounter lines. (impl. left as homework)

  • Use a global line count variable. (impl. left as homework)

Related