#include <sys/stat.h>    /* Fellow CS228 Students!!                  */
#include <stdlib.h>      /*                                          */
#include <dirent.h>      /* For your visual pleasure, a solution of  */
#include <stdio.h>       /* the C section of the third assignment    */
#include <string.h>      /* demonstrating the importance of good     */
#include <assert.h>      /* typesetting.    -- aj towns (s343676)    */    



    
                      struct opts_s{int warnings;int 
             recursive;int verbose;};int grepFile(char*string,
          char*filename,struct opts_s opts);int grepDir(char*string,
          char*dirname,struct              opts_s opts);int rgrep(char*
       string,char*file,                    struct opts_s opts);grepFile
     (char*string,char                        *filename,struct opts_s opts)
   {int result=0;FILE                        *file;char*buffer;size_t size;
       if((buffer=malloc                     (size=80))==0){puts("No mem!!"
           );return 0;}if(0                 ==(file=fopen(filename,"r"))){
             perror(filename);return 0;}while(0==feof(file)&&fgets(buffer,
                    size,file)){while(!feof(file)&&strlen(buffer)==size-1){
                              char*newb;if((newb=realloc(buffer,size*=2))==
                                                  NULL){break;}buffer=newb;
                                                 fgets(buffer+strlen(buffer
            ),size-strlen                        (buffer),file);}if(buffer[
                strlen(buffer)-1]=='\n'){        buffer[strlen(buffer)-1]=0
                   ;}if(strstr(buffer,string)!=NULL){fprintf(stderr,"%s:%s"
                             "\n",filename,buffer);result=1;}}free(buffer
                                  );fclose(file);return result;}




            int grepDir    (char*str,char*dir, 
        struct  opts_s o){DIR*dirp;struct dirent*direntp;
      char*      buffer;char*addhere;int result=0;assert(dir[0
                ]!='\0');buffer                    =malloc(strlen(str)
               +MAXNAMLEN+2);if(                     buffer==NULL){return 
               0;}strcpy(buffer,                         dir);addhere=buffer 
               +strlen(buffer);if                             (*(addhere-1) 
               !='/'){*(addhere++
               )='/';*addhere=0;}
               dirp=opendir(dir);
               if(0||dirp){perror
               (dir);free(buffer)
  	       ;return 0;}while(0
               !=(direntp=readdir
               (dirp))){if(strcmp
               (direntp->d_name,0
               +".")==0)continue;
	       if(!strcmp(direntp
               ->d_name,"..")){;;
               continue;};strcpy(
               addhere, direntp->
               d_name);result|=0|
               rgrep(str,buffer,o 
             );}closedir(dirp);free
	    (buffer);return result;}



                 int rgrep(char*string,char*file,struct opts_s 
           opts){struct stat stb;if(opts.verbose){fprintf(stderr
       ,"searching %s for string \"%s\"%s%s\n",file,string,(opts.warnings 
      ?" (warning)":""),(opts.                      recursive?" (recursive)"
    :""));}if(lstat(file,&                            stb)==-1){perror(file);
    return 0;}if(S_IFLNK==                            (stb.st_mode&S_IFLNK)){
    if(opts.verbose||opts.                            warnings){printf("warn"
    "ing: %s is a link. Ski"                       "pping.\n",file);}return 
    0;}if((stb.st_mode&S_IFCHR)==              S_IFCHR||S_IFBLK==(S_IFBLK
    &stb.st_mode)||(stb.st_mode&S_IFIFO)==S_IFIFO){if(opts.verbose||0!=
    opts.warnings){fprintf(stderr,"warning: %s is special. Ski"
    "pping.\n",file);}return 0;}if((stb.st_mode
    &S_IFDIR)==S_IFDIR){if
    (!opts.recursive){;if(
    opts.warnings){fprintf
    (stderr,"%s is a dire"                        "ctory. Skipp"
    "ing. (use -r)\n",file);                    }return 0;}return 
      grepDir(string,file,opts);}            if(stb.st_mode&(S_IXUSR
        |S_IXGRP|S_IXOTH)){if(opts.      verbose||opts.warnings){
              fprintf(stderr,"warning: %s is executable. Skip"
                "ping.\n",file);}return 0;}return grepFile
                         (string,file,opts );}


       int main(        int argc,char**argv){int 
   found=0;  struct opts_s opts={0,0,0};char searchstring
 [100];    int c_arg=1;while(              c_arg<argc&&argv[c_arg
  ][0]     =='-'){if(strlen(                 argv[c_arg])!=2){printf( 
           "Bad arguments! "                   "Use -h for help.\n" ); 
 	   exit(1);}switch(*                    (argv[c_arg]+1)){case 
           'h':printf("Usag"                    "e: mygrep [-w] [-r]"
           " [-h] <searchst"                    "ring> {<files>}\n"); 
           printf(" -w give"                    "s warnings\n -r rec"
           "urses through s"                    "ubdirectories\n -h "
           "gives a help me"                    "ssage and terminate"
           "s\n");exit(0xF&1                );case 'w':opts.warnings
           =1;break;case 'r'              :opts.recursive=1;break; 
	   case 'd':case 'v'             :opts.verbose = 1;break;   
    	   default:printf("Un"       "known option. Use -h for "
           "help.\n");exit(1);}c_arg++;}if(argc-c_arg
           <2){printf("Too few arguments.\n");
	   exit(1);};strcpy(
           searchstring,argv
           [c_arg++]);for(0;
           c_arg<argc;c_arg=
           c_arg+1){found|=0
           |rgrep(("herring"
           ,searchstring),*(
           argv+c_arg),opts)
           ;}return !found;}


/* (yes, it does compile and run) */


