Kjetil's Information Center: A Blog About My Projects

Recursive String Search

Here is another one of those simple programs that are missing on the Windows platform; a functioning string search tool! The program's scheme is somewhat similar to using the UNIX grep command's combination of the '-n' '-i' and '-r' switches. It will search in a directory and it's sub-directories for a fixed case-insensitive string and display the name of each file, the line number and the line itself where that string is found.

Here's is a link to the binary for Win32 (compiled with MinGW) and here's the source code:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <unistd.h>
#include <dirent.h>

static char line[1024];

static void recurse(char *path, char *string, int len)
{
  char full_path[PATH_MAX];
  int n, match, name_shown, line_no;
  struct dirent *entry;
  struct stat st;
  DIR *dh;
  FILE *fh;

  dh = opendir(path);
  if (dh == NULL) {
    fprintf(stderr, "Warning: Unable to open directory: %s\n", path);
    return;
  }

  while ((entry = readdir(dh))) {
    if (entry->d_name[0] == '.')
      continue; /* Ignore files with leading dot. */

#ifdef WINNT
    snprintf(full_path, PATH_MAX, "%s\\%s", path, entry->d_name);
#else
    snprintf(full_path, PATH_MAX, "%s/%s", path, entry->d_name);
#endif

    stat(full_path, &st);
    if (S_ISDIR(st.st_mode)) {
      /* Traverse. */
      recurse(full_path, string, len);
    } else if (S_ISREG(st.st_mode)) {
      /* Search. */
      fh = fopen(full_path, "r");
      if (fh == NULL) {
        fprintf(stderr, "Warning: Unable to open file: %s\n", full_path);
        continue;
      }
      name_shown = line_no = 0;
      while (fgets(line, 1024, fh) != NULL) {
        line_no++;
        match = 0;
        for (n = 0; line[n] != '\0'; n++) {
          if (toupper(line[n]) == toupper(string[match])) {
            match++;
            if (match >= len) {
              if (! name_shown) {
                printf("%s\n", full_path);
                name_shown = 1;
              }
              printf("%d:%s", line_no, line);
              break;
            }
          } else {
            match = 0;
          }
        }
      }
      fclose(fh);
    }
  }

  closedir(dh);
  return;
}

int main(int argc, char *argv[])
{

  if (argc != 3) {
    fprintf(stderr, "Usage: %s <directory> <string>\n", argv[0]);
    return 1;
  }

  recurse(argv[1], argv[2], strlen(argv[2]));
  return 0;
}
          


Topic: Scripts and Code, by Kjetil @ 01/10-2011, Article Link