Wednesday, April 9, 2014

Updated Text Search Utility (Source Code)


// TSUNAMI - Text Search Utility
//--------------------
// Searches files for multiple text strings
//
//   - Takes up to 10 search strings
//   - Searches up to 10 file types
//   - Accepts wildcards (*, ?) in file types
//   - Optionally searches subdirectories
//   - Optionally searches hidden files/directories
//   - Program can be paused or aborted early
//   - Handles both text and binary files
//   - All search strings must be found in file
//   - Writes search results (file name and path) to
//     TSUNAMI.OUT in current working directory
//

#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <dir.h>
#include <dos.h>
#include <string.h>


const MAX_STRING = 512;
const MAX_LIST   =  10;
const MAX_FNAME  =  13;  // max. field length for file types
const MAX_SSTR   =  64;  // max. field length for search strings

struct ft_list {
 char array[MAX_LIST][MAX_FNAME];
 int  count;
};

struct ss_list {
 char array[MAX_LIST][MAX_SSTR];
 int  count;
};

struct ft_list FLIST;  // stores file types to search in
struct ss_list SLIST;  // stores strings to search for

char SRCH_DIR[MAX_STRING];
char ORIG_DIR[MAX_STRING];

const YES = 1;
const NO  = 0;

int DO_SUBDIRS;
int DO_HIDDEN;
int DO_OPTIMIZE;

int RESULTS_COUNT = 0;

char RESULTS_FILE[MAX_FNAME] = "TSUNAMI.OUT";  // output file

FILE *results_fptr;


//--------------------------------------------------------
void pause (void)
{
 printf("\nPress any key... \n");
 while (!kbhit());
}


//-----------------------------
int file_exist (const char *fname)
{
 struct ffblk ffblk;

 return(findfirst(fname, &ffblk, FA_DIREC+FA_HIDDEN));
}

//--------------------------------------------------------
char *upstr (char *s)
{
 int i;

 for (i = 0; s[i] != 0; i++) s[i] = toupper(s[i]);
 return (s);
} // upstr


//--------------------------------------------------------
int get_ext_key (char k)
{
 if (k == 0) k = getch();
 return (k);
} // get_ext_key


//--------------------------------------------------------
char *get_input (char *s, int max_len)
// s is the default input string to display
// max_len is the maximum length for input + 1
// length of s MUST be <= max_len <= MAX_STRING
{
 char t[MAX_STRING] = {'\0'};
 int i, key;

 if (max_len > MAX_STRING) max_len = MAX_STRING;  // keep in range
 strcpy(t, s);
 i = strlen(s);
 printf("%s", s);
 while (!kbhit())
 {
  switch(key = getch())
  {
   case  0:  // EXTENDED KEY
   {
    key = get_ext_key(key);
    break;
   }
   case  8:  // BACKSPACE
   {
    if (i > 0)
    {
     putch(key);
     putch(' ');
     putch(key);
     t[--i] = '\0';
    }
    break;
   }
   case 13:  // RETURN
   {
    putch('\n');
    putch(key);
    strcpy(s, t);
    return(s);
   }
   case 27:  // ESCAPE
   {
    putch('\n');
    putch('\r');
    s = "";
    return(s);
   }
   default:
   {
    if (i < max_len-1)  // allow for ending null
    {
     putch(key);
     t[i] = key;
     i++;
     t[i] = '\0';
     break;
    }
   }
  }
 }
 return (s);
} // get_input


//--------------------------------------------------------
void user_interrupt (void)
{
 int key = 0;

 switch (key = (int) toupper(getch()))
 {
  case 'P': // PAUSE
   {
    printf("\rPausing. Press any key to continue...");
    clreol();
    while (!kbhit());
    break;
   }
  case 27:  // ESCAPE
   {
    printf("\rAborting TSUNAMI");
    clreol();
    printf("\n\n%d results saved in %s\n", RESULTS_COUNT, RESULTS_FILE);
    chdir(ORIG_DIR);
    exit(1);
   }
  default:
   {
   }
 }
} // user_interrupt


//--------------------------------------------------------
void input_search_directory (void)
{
 char s[MAX_STRING] = {'\0'};

 strcpy(s, "C:\\DOCUME~1\\ADMINI~1\\MYDOCU~1\\DOWNLO~1");
 printf("Specify directory to search in:\n");
 do
 {
  strcpy(SRCH_DIR, upstr(get_input(s, MAX_STRING)));
  if (SRCH_DIR[0] == '\0')
  {
   printf("\nAborting TSUNAMI...\n");
   exit(1);
  }
  if (SRCH_DIR[strlen(SRCH_DIR)-1] == '\\')
   SRCH_DIR[strlen(SRCH_DIR)-1] = '\0';
  if (file_exist(SRCH_DIR) != 0)
   printf("\nERROR: Directory does not exist. Try again:\n");
  strcpy(s, "");
 }
 while (file_exist(SRCH_DIR) != 0);
} // input_search_directory


//--------------------------------------------------------
int toggle_YN (char *s)
{
 char ch;

 printf("%s", s);
 do
  ch = toupper(getch());
 while ((ch != 'Y') && (ch != 'N'));
 printf("%c\n", ch);
 if (ch == 'Y') return(YES); else return(NO);
} // toggle_YN


//--------------------------------------------------------
void input_search_strings (void)
{
 char s[MAX_SSTR] = {'\0'};

 SLIST.count = 0;
 printf("Specify search strings (max. 10):\n");
 while (SLIST.count < MAX_LIST)
 {
  strcpy(s, "");
  printf("%d) ", SLIST.count+1);
  strcpy(s, get_input(s, MAX_SSTR));
  if (s[0] == '\0') break;
  strcpy(SLIST.array[SLIST.count], s);
  SLIST.count++;
 }
} // input_search_strings


//--------------------------------------------------------
void input_file_strings (void)
{
 char s[MAX_FNAME] = {'\0'};

 FLIST.count = 0;
 printf("Specify file types to search for (max. 10):\n");
 while (FLIST.count < MAX_LIST)
 {
  strcpy(s, "*.*");
  printf("%d) ", FLIST.count+1);
  strcpy(s, upstr(get_input(s, MAX_FNAME)));
  if (s[0] == '\0') break;
  strcpy(FLIST.array[FLIST.count], s);
  FLIST.count++;
 }
} // input_file_strings


//--------------------------------------------------------
int search_file_for_string (char *fname, char *s)
{
 FILE *fptr;
 struct ffblk ffblk;
 char ch;
 int len;
 int  si = 0;      // search string index
 long fi = 0;      // file index

 len = strlen(s);
 if ((fptr = fopen(fname, "rb")) != NULL)
 {
  findfirst(fname, &ffblk, FA_HIDDEN);
  while (fi < ffblk.ff_fsize)
  {
   ch = fgetc(fptr);
   fi++;
   // convert special characters to spaces
   if ((ch == '\n') || (ch == '\r') || (ch == '\t') || (ch == '\0'))
    ch = ' ';
   if ((ch == s[si]) && (si < len))
   {
    si++;
    if (si == len)
    {
     fclose(fptr);
     return(1);
    }
   }
   else si = 0;
  }
  fclose(fptr);
 }
 return(0);
} // search_file_for_string


//--------------------------------------------------------
void save_results_to_file (char *fname)
{
 char cwd[MAX_STRING] = {'\0'};

 getcwd(cwd, MAX_STRING);
 if (cwd[3] != '\0') strcat(cwd, "\\");
 fprintf(results_fptr, "%s%s\n", cwd, fname);
 if (!DO_OPTIMIZE) printf("\n");
} // save_results_to_file


//--------------------------------------------------------
void search_for_strings (char *fname)
{
 int i, n;

 n = 0;
 for (i = 0; i < SLIST.count; i++)
 {
  if (search_file_for_string(fname, SLIST.array[i]) == 0) break;
  if (kbhit()) user_interrupt();  // check for pause or abort
  n++;
 }
 if ((n > 0) && (n == SLIST.count))
 {
  RESULTS_COUNT++;
  save_results_to_file(fname);
 }
} // search_for_strings


//--------------------------------------------------------
void search_for_files (char *fname)
{
 struct ffblk ffblk;
 char cwd[MAX_STRING] = {'\0'};
 int att = 0;
 int done;

 getcwd(cwd, MAX_STRING);
 if (cwd[3] != '\0') strcat(cwd, "\\");
 if (DO_HIDDEN == YES) att = FA_HIDDEN;
 done = findfirst(fname, &ffblk, att);
 while (!done)
 {
  if (DO_OPTIMIZE == YES)
   search_for_strings(ffblk.ff_name);
  else
  {
   printf("\r%s%s", cwd, ffblk.ff_name);
   clreol();
   search_for_strings(ffblk.ff_name);
   printf("\r");
   clreol();
  }
  done = findnext(&ffblk);
 }
 if (DO_SUBDIRS == YES)
 {
  att = att + FA_DIREC;
  done = findfirst("*.*", &ffblk, att);
  while (!done)
  {
   if (ffblk.ff_attrib & FA_DIREC)
   {
    if (ffblk.ff_name[0] != '.')
    {
     chdir(ffblk.ff_name);
     search_for_files(fname);
     chdir("..");
    }
   }
   done = findnext(&ffblk);
  }
 }
} // search_for_files



//--------------------------------------------------------
int main (void)
{
 int i;

 clrscr();
 input_search_directory();
 DO_SUBDIRS  = toggle_YN("Search subdirectories? [Y/N]: ");
 DO_HIDDEN   = toggle_YN("Search hidden files/directories? [Y/N]: ");
 DO_OPTIMIZE = toggle_YN("Full optimization (no screen output)? [Y/N]: ");
 input_search_strings();
 input_file_strings();
 getcwd(ORIG_DIR, MAX_STRING);
 if ((results_fptr = fopen(RESULTS_FILE, "wt")) != NULL)
 {
  chdir(SRCH_DIR);
  printf("Press (P) to Pause, (ESC) to Abort...
  for (i = 0; i < FLIST.count; i++)
   search_for_files(FLIST.array[i]);
  chdir(ORIG_DIR);
  fclose(results_fptr);
  printf("\n%d results in %s\n", RESULTS_COUNT, RESULTS_FILE);
  pause();
 }
 return(0);
}

No comments:

Post a Comment