Guest User

Untitled

a guest
Dec 14th, 2017
77
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.51 KB | None | 0 0
  1. /**********************************
  2. * finder.c
  3. *
  4. * CS50 AP
  5. * Finder
  6. *
  7. * Searches for a target string in
  8. * all files in a directory
  9. * Modified by Daniel Lawson
  10. *
  11. **********************************/
  12.  
  13. #define _BSD_SOURCE
  14. #define _GNU_SOURCE
  15.  
  16. #include <cs50.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <dirent.h>
  21.  
  22. // struct to hold the file name and type
  23. typedef struct
  24. {
  25. string name;
  26. string type;
  27. }
  28. path;
  29.  
  30. // struct to hold the directory info
  31. typedef struct
  32. {
  33. string name;
  34. int npaths;
  35. path* paths;
  36. }
  37. directory;
  38.  
  39. // string to hold the word to seek
  40. string key;
  41.  
  42. // the function to search for files in a directory and populate the struct
  43. directory populate(directory dir);
  44.  
  45. // the function to recursively iterate through directories and handle files
  46. int seek(directory dir);
  47.  
  48. // main - sets arguments and calls the seek function
  49. int main(int argc, char* argv[])
  50. {
  51.  
  52. // TODO: ensure proper number of command line arguments
  53. if(argc != 2 && argc != 3)
  54. {
  55. printf("Enter valid arguments! (./finder foo or ./finder foo bar)\n");
  56. return 1;
  57. }
  58. //store key value
  59. key = argv[1];
  60. // create initial directory
  61. directory dir;
  62.  
  63. // TODO: set "dir"s name based on command line arguments entered
  64. if(argc == 3){
  65. dir.name = argv[2];
  66. }
  67. else
  68. {
  69. dir.name = "./";
  70. }
  71. // call the seek function
  72. seek(dir);
  73. return 0;
  74. }
  75.  
  76. // for a given directory, searches for files and fills array in the struct
  77. directory populate(directory dir)
  78. {
  79. // initialize all pointers and values in the given struct
  80. dir.npaths = 0;
  81. dir.paths = NULL;
  82. DIR* dirp;
  83. struct dirent* entry;
  84.  
  85. // opendir is a system call that opens a "directory stream" containing
  86. // information about all files in the given directory (represented here
  87. // by dir.name)
  88. dirp = opendir(dir.name);
  89. if (dirp == NULL)
  90. {
  91. printf("Opening directory failed. Check your input filepath!\n");
  92. return dir;
  93. }
  94.  
  95. // while directory stream still contains files, seek through them
  96. while((entry = readdir(dirp)) != NULL)
  97. {
  98. // if entry is a directory and not '.' or '..',
  99. // increase file count and populate the struct
  100. if (entry->d_type == DT_DIR && strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0)
  101. {
  102. // allocate zeroed-out memory for the construction of the file name
  103. string name = calloc(1, strlen(dir.name) + strlen(entry->d_name) + 2);
  104. strcat(name, dir.name);
  105. strcat(name, entry->d_name);
  106. strcat(name, "/");
  107.  
  108. // reallocate memory to expand the array
  109. dir.paths = realloc(dir.paths, (dir.npaths + 1) * sizeof(path));
  110.  
  111. // add a new element to the array containing names and types
  112. path newPath = {.name = name, .type = "directory"};
  113. dir.paths[dir.npaths] = newPath;
  114.  
  115. // increase file count for the directory
  116. dir.npaths++;
  117. }
  118.  
  119. // else if entry is a file, increase file count and populate the struct
  120. else if (entry->d_type == DT_REG)
  121. {
  122. // allocate zeroed-out memory for the construction of the file name
  123. string name = calloc(1, strlen(dir.name) + strlen(entry->d_name) + 1);
  124. strcat(name, dir.name);
  125. strcat(name, entry->d_name);
  126.  
  127. // reallocate memory to expand the array
  128. dir.paths = realloc(dir.paths, (dir.npaths + 1) * sizeof(path));
  129.  
  130. // add a new element to the array containing names and types
  131. path newPath = {.name = name, .type = "file"};
  132. dir.paths[dir.npaths] = newPath;
  133.  
  134. // increase file count for the directory
  135. dir.npaths++;
  136. }
  137. }
  138.  
  139. // close directory stream using system call closedir and return struct
  140. closedir(dirp);
  141. return dir;
  142.  
  143. }
  144.  
  145. // recursive function to iterate through directories and search files
  146. int seek(directory dir)
  147. {
  148. //popuate directory
  149. dir = populate(dir);
  150. //look at each path
  151. for(int i = 0; i < dir.npaths; i++)
  152. {
  153. //if the current path is a file, and not found.txt or ./finder
  154. if(strcmp(dir.paths[i].type,"file") == 0 && strcmp(dir.paths[i].name,"./found.txt") != 0 && strcmp(dir.paths[i].name,"./finder") != 0)
  155. {
  156. //create a file reader
  157. FILE *fr = fopen(dir.paths[i].name,"r");
  158. //make sure reader is not null
  159. if(fr == NULL)
  160. {
  161. printf("invalid path: %s\n",dir.paths[i].name);
  162. return 1;
  163. }
  164. //create an array to store words in the file
  165. char word[50];
  166. //create a boolean to keep track if it is the first time a word is found in the file
  167. bool found = false;
  168. //run the while loop until we are at the end of the file
  169. while(fgets(word,sizeof(word),fr) != NULL)
  170. {
  171.  
  172. //for debugging
  173. /*if(strcmp(dir.paths[i].name,"./dogs.txt") == 0)
  174. {
  175. printf("the word in the file is: %s\n",word);
  176. }*/
  177. //create a string to store the substring
  178. char *sub;
  179. //try find and assign a substring in the current words of the file
  180. sub = strstr(word,key);
  181. //if a substring is not found, assign sub to all the current words
  182. if(sub == NULL)
  183. {
  184. sub = word;
  185. }
  186. /*
  187. if sub is longer than key, add a null terminator sub so that it is the same size of
  188. key. Substring returns a pointer to the start of the string, for example
  189. if you had a sentence, like: "dogs are great!" , and you are looking for great
  190. strstr would give you a pointer to the start of great, but would contain
  191. also the !. Adding a null terminator to the character in the equivalent spot
  192. in the key makes the later usage of strcmp properly work.
  193. */
  194. if(strlen(sub) > strlen(key))
  195. {
  196. sub[strlen(key)] = '\0';
  197. }
  198. //compare the substring to the key
  199. if(strcmp(sub,key) == 0)
  200. {
  201. //printf("found in %s\n", dir.paths[i].name); //optional print
  202. //begin appending to found.txt
  203. FILE *fw = fopen("found.txt","a");
  204. if (fw == NULL)
  205. {
  206. printf("problems writing to found.txt\n");
  207. return 1;
  208. }
  209. //if the first time, also print information about the file
  210. if(!found)
  211. {
  212. fputs("for keyword ",fw);
  213. fputs(key,fw);
  214. fputs(" in ",fw);
  215. fputs(dir.paths[i].name,fw);
  216. fputs(":\n",fw);
  217. found = true;
  218. }
  219. //print the word
  220. fputs(key,fw);
  221. fputs("\n",fw);
  222. fclose(fw);
  223. }
  224. }
  225. fclose(fr);
  226. }
  227. //if a directory, make a new directory and do a recursive call to seek
  228. else if(strcmp(dir.paths[i].type,"directory") == 0)
  229. {
  230. directory nDir;
  231. nDir.name = dir.paths[i].name;
  232. seek(nDir);
  233. }
  234. }
  235. return 0;
  236. }
Add Comment
Please, Sign In to add comment