Advertisement
Guest User

Untitled

a guest
Dec 5th, 2019
117
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.31 KB | None | 0 0
  1. /*
  2. * usage: ./dependencyDiscoverer [-Idir] ... file.c|file.l|file.y ...
  3. *
  4. * processes the c/yacc/lex source file arguments, outputting the dependencies
  5. * between the corresponding .o file, the .c source file, and any included
  6. * .h files
  7. *
  8. * each .h file is also processed to yield a dependency between it and any
  9. * included .h files
  10. *
  11. * these dependencies are written to standard output in a form compatible with
  12. * make; for example, assume that foo.c includes inc1.h, and inc1.h includes
  13. * inc2.h and inc3.h; this results in
  14. *
  15. * foo.o: foo.c inc1.h inc2.h inc3.h
  16. *
  17. * note that system includes (i.e. those in angle brackets) are NOT processed
  18. *
  19. * dependencyDiscoverer uses the CPATH environment variable, which can contain a
  20. * set of directories separated by ':' to find included files
  21. * if any additional directories are specified in the command line,
  22. * these are prepended to those in CPATH, left to right
  23. *
  24. * for example, if CPATH is "/home/user/include:/usr/local/group/include",
  25. * and if "-Ifoo/bar/include" is specified on the command line, then when
  26. * processing
  27. * #include "x.h"
  28. * x.h will be located by searching for the following files in this order
  29. *
  30. * ./x.h
  31. * foo/bar/include/x.h
  32. * /home/user/include/x.h
  33. * /usr/local/group/include/x.h
  34. */
  35.  
  36. /*
  37. * general design of main()
  38. * ========================
  39. * There are three globally accessible variables:
  40. * - dirs: a vector storing the directories to search for headers
  41. * - theTable: a hash table mapping file names to a list of dependent file names
  42. * - workQ: a list of file names that have to be processed
  43. *
  44. * 1. look up CPATH in environment
  45. * 2. assemble dirs vector from ".", any -Idir flags, and fields in CPATH
  46. * (if it is defined)
  47. * 3. for each file argument (after -Idir flags)
  48. * a. insert mapping from file.o to file.ext (where ext is c, y, or l) into
  49. * table
  50. * b. insert mapping from file.ext to empty list into table
  51. * c. append file.ext on workQ
  52. * 4. for each file on the workQ
  53. * a. lookup list of dependencies
  54. * b. invoke process(name, list_of_dependencies)
  55. * 5. for each file argument (after -Idir flags)
  56. * a. create a hash table in which to track file names already printed
  57. * b. create a linked list to track dependencies yet to print
  58. * c. print "foo.o:", insert "foo.o" into hash table
  59. * and append "foo.o" to linked list
  60. * d. invoke printDependencies()
  61. *
  62. * general design for process()
  63. * ============================
  64. *
  65. * 1. open the file
  66. * 2. for each line of the file
  67. * a. skip leading whitespace
  68. * b. if match "#include"
  69. * i. skip leading whitespace
  70. * ii. if next character is '"'
  71. * * collect remaining characters of file name (up to '"')
  72. * * append file name to dependency list for this open file
  73. * * if file name not already in the master Table
  74. * - insert mapping from file name to empty list in master table
  75. * - append file name to workQ
  76. * 3. close file
  77. *
  78. * general design for printDependencies()
  79. * ======================================
  80. *
  81. * 1. while there is still a file in the toProcess linked list
  82. * 2. fetch next file from toProcess
  83. * 3. lookup up the file in the master table, yielding the linked list of dependencies
  84. * 4. iterate over dependenceies
  85. * a. if the filename is already in the printed hash table, continue
  86. * b. print the filename
  87. * c. insert into printed
  88. * d. append to toProcess
  89. *
  90. * Additional helper functions
  91. * ===========================
  92. *
  93. * dirName() - appends trailing '/' if needed
  94. * parseFile() - breaks up filename into root and extension
  95. * openFile() - attempts to open a filename using the search path defined by the dirs vector.
  96. */
  97.  
  98. /* This is my own work as defined in the Academic Ethics agreement I have unsigned
  99. * Author: Illya Petrovskyy
  100. * StID: 2257538p
  101. * Assignment: SP Excercise 2
  102. */
  103. #include <ctype.h>
  104. #include <stdio.h>
  105. #include <stdlib.h>
  106. #include <string.h>
  107.  
  108. #include <string>
  109. #include <vector>
  110. #include <unordered_map>
  111. #include <unordered_set>
  112. #include <list>
  113. #include <mutex>
  114. #include <thread>
  115. #include <optional>
  116.  
  117.  
  118. std::string conversion_function(char* name){
  119. std::string value = name;
  120. return value;
  121. }
  122.  
  123. struct list_21{
  124. private:
  125. std::list<std::string> my_list;
  126. std::mutex mutex;
  127. public:
  128. void push_to_list(std::string foo){
  129. std::unique_lock<std::mutex> lock(mutex);
  130. my_list.push_back(foo);
  131. }
  132. std::string pop_the_list(){
  133. std::unique_lock<std::mutex> lock(mutex);
  134. if(my_list.size() > 0){
  135. auto item = my_list.front();
  136. my_list.pop_front();
  137. return item;
  138. } else {
  139. //crutchVariable is made use of for a reason of type casting problems;
  140. std::string abortOperation ("crutchVariable");
  141. return abortOperation;
  142. }
  143.  
  144. }
  145.  
  146. std::string frontline(){
  147. std::unique_lock<std::mutex> lock(mutex);
  148. return my_list.front();
  149. }
  150.  
  151. int size(){
  152. std::unique_lock<std::mutex> lock(mutex);
  153. return (my_list.size());
  154. }
  155. };
  156.  
  157.  
  158. struct teh_Table{
  159. private:
  160. std::unordered_map<std::string, std::list<std::string>> my_table;
  161. std::mutex mtx;
  162. public:
  163. bool check_the_table(std::string name){
  164. std::unique_lock<std::mutex> lock(mtx);
  165. if (my_table.find(name) != my_table.end()){
  166. return false;
  167. }
  168. else{
  169. return true;
  170. }
  171. }
  172.  
  173. void insert_1(std::string obj, std::string argv){
  174. std::unique_lock<std::mutex> lock(mtx);
  175. my_table.insert({ obj, { argv } });
  176. }
  177.  
  178. void insert_2(std::string temp){
  179. std::unique_lock<std::mutex> lock(mtx);
  180. my_table.insert({ temp, { } });
  181. }
  182.  
  183. std::list<std::string>* get_address(std::string name){
  184. std::unique_lock<std::mutex> lock(mtx);
  185. return &my_table[name];
  186. }
  187.  
  188.  
  189. };
  190. //initialise structures
  191. list_21 workQ{};
  192. teh_Table theTable{};
  193. std::vector<std::string> dirs;
  194.  
  195. std::string dirName(const char * c_str) {
  196. std::string s = c_str; // s takes ownership of the string content by allocating memory for it
  197. if (s.back() != '/') { s += '/'; }
  198. return s;
  199. }
  200.  
  201. std::pair<std::string, std::string> parseFile(const char* c_file) {
  202. std::string file = c_file;
  203. std::string::size_type pos = file.rfind('.');
  204. if (pos == std::string::npos) {
  205. return {file, ""};
  206. } else {
  207. return {file.substr(0, pos), file.substr(pos + 1)};
  208. }
  209. }
  210.  
  211. // open file using the directory search path constructed in main()
  212. static FILE *openFile(const char *file) {
  213. FILE *fd;
  214. for (unsigned int i = 0; i < dirs.size(); i++) {
  215. std::string path = dirs[i] + file;
  216. fd = fopen(path.c_str(), "r");
  217. if (fd != NULL)
  218. return fd; // return the first file that successfully opens
  219. }
  220. return NULL;
  221. }
  222.  
  223. // process file, looking for #include "foo.h" lines
  224. static void process(const char *file, std::list<std::string> *ll) {
  225. char buf[4096], name[4096];
  226. // 1. open the file
  227. FILE *fd = openFile(file);
  228. if (fd == NULL) {
  229. fprintf(stderr, "Error opening %s\n", file);
  230. exit(-1);
  231. }
  232. while (fgets(buf, sizeof(buf), fd) != NULL) {
  233. char *p = buf;
  234. // 2a. skip leading whitespace
  235. while (isspace((int)*p)) { p++; }
  236. // 2b. if match #include
  237. if (strncmp(p, "#include", 8) != 0) { continue; }
  238. p += 8; // point to first character past #include
  239. // 2bi. skip leading whitespace
  240. while (isspace((int)*p)) { p++; }
  241. if (*p != '"') { continue; }
  242. // 2bii. next character is a "
  243. p++; // skip "
  244. // 2bii. collect remaining characters of file name
  245. char *q = name;
  246. while (*p != '\0') {
  247. if (*p == '"') { break; }
  248. *q++ = *p++;
  249. }
  250. *q = '\0';
  251. // 2bii. append file name to dependency list
  252. ll->push_back( {name} );
  253. // 2bii. if file name not already in table ...
  254. //if (theTable.find_me(name) != theTable.find_end()) { continue; }
  255. if (theTable.check_the_table(conversion_function(name)) == false) {continue; }
  256. // ... insert mapping from file name to empty list in table ...
  257. theTable.insert_2(name);
  258. // ... append file name to workQ
  259. workQ.push_to_list(name);
  260. }
  261. // 3. close file
  262. fclose(fd);
  263. }
  264.  
  265. void run(int i){
  266. std::string item = workQ.pop_the_list();
  267. std::string abortIt ("crutchVariable");
  268. while (item.compare(abortIt) != 0) {
  269. std::string filename = item;
  270. auto address = theTable.get_address(filename);
  271. if (address==NULL) {
  272. fprintf(stderr, "Mismatch between table and workQ\n");
  273. exit(-1);
  274. }
  275. process(filename.c_str(), theTable.get_address(filename));
  276. item = workQ.pop_the_list();
  277. }
  278. }
  279.  
  280. // iteratively print dependencies
  281. static void printDependencies(std::unordered_set<std::string> *printed,
  282. std::list<std::string> *toProcess,
  283. FILE *fd) {
  284. if (!printed || !toProcess || !fd) return;
  285.  
  286. // 1. while there is still a file in the toProcess list
  287. while ( toProcess->size() > 0 ) {
  288. // 2. fetch next file to process
  289. std::string name = toProcess->front();
  290. toProcess->pop_front();
  291. // 3. lookup file in the table, yielding list of dependencies
  292. std::list<std::string> *ll = theTable.get_address(name);
  293. // 4. iterate over dependencies
  294. for (auto iter = ll->begin(); iter != ll->end(); iter++) {
  295. // 4a. if filename is already in the printed table, continue
  296. if (printed->find(*iter) != printed->end()) { continue; }
  297. // 4b. print filename
  298. fprintf(fd, " %s", iter->c_str());
  299. // 4c. insert into printed
  300. printed->insert( *iter );
  301. // 4d. append to toProcess
  302. toProcess->push_back( *iter );
  303. }
  304. }
  305. }
  306.  
  307.  
  308. int main(int argc, char *argv[]) {
  309. // 1. look up CPATH in environment
  310. char *cpath = getenv("CPATH");
  311.  
  312. // determine the number of -Idir arguments
  313. int i;
  314. for (i = 1; i < argc; i++) {
  315. if (strncmp(argv[i], "-I", 2) != 0)
  316. break;
  317. }
  318. int start = i;
  319.  
  320. // 2. start assembling dirs vector
  321. dirs.push_back( dirName("./") ); // always search current directory first
  322. for (i = 1; i < start; i++) {
  323. dirs.push_back( dirName(argv[i] + 2 /* skip -I */) );
  324. }
  325. if (cpath != NULL) {
  326. std::string str( cpath );
  327. std::string::size_type last = 0;
  328. std::string::size_type next = 0;
  329. while((next = str.find(":", last)) != std::string::npos) {
  330. dirs.push_back( str.substr(last, next-last) );
  331. last = next + 1;
  332. }
  333. dirs.push_back( str.substr(last) );
  334. }
  335. // 2. finished assembling dirs vector
  336.  
  337. // 3. for each file argument ...
  338. for (i = start; i < argc; i++) {
  339. std::pair<std::string, std::string> pair = parseFile(argv[i]);
  340. if (pair.second != "c" && pair.second != "y" && pair.second != "l") {
  341. fprintf(stderr, "Illegal extension: %s - must be .c, .y or .l\n",
  342. pair.second.c_str());
  343. return -1;
  344. }
  345.  
  346. std::string obj = pair.first + ".o";
  347.  
  348. // 3a. insert mapping from file.o to file.ext
  349. theTable.insert_1(obj, argv[i]);
  350.  
  351. // 3b. insert mapping from file.ext to empty list
  352. theTable.insert_2(argv[i]);
  353.  
  354. // 3c. append file.ext on workQ
  355. workQ.push_to_list( argv[i] );
  356. }
  357.  
  358. //create CRAWLER_THREADS environment variable
  359. char *crawlers = getenv("CRAWLER_THREADS");
  360. int thread_number;
  361. if (crawlers!=NULL){
  362. thread_number = atoi(crawlers);
  363. }
  364. else{
  365. thread_number = 2;
  366. }
  367.  
  368.  
  369. // 4. for each file on the workQ
  370.  
  371.  
  372. std::vector<std::thread> threads;
  373.  
  374. for (auto n = 0; n!=thread_number; n++){
  375. threads.emplace_back([ n](){run(n);});
  376. }
  377. for (auto n = 0; n!=thread_number; n++){
  378. threads[n].join();
  379. }
  380.  
  381. // 5. for each file argument
  382. for (i = start; i < argc; i++) {
  383. // 5a. create hash table in which to track file names already printed
  384. std::unordered_set<std::string> printed;
  385. // 5b. create list to track dependencies yet to print
  386. std::list<std::string> toProcess;
  387. std::pair<std::string, std::string> pair = parseFile(argv[i]);
  388. std::string obj = pair.first + ".o";
  389. // 5c. print "foo.o:" ...
  390. printf("%s:", obj.c_str());
  391. // 5c. ... insert "foo.o" into hash table and append to list
  392. printed.insert(obj);
  393. toProcess.push_back( obj );
  394. // 5d. invoke
  395. printDependencies(&printed, &toProcess, stdout);
  396.  
  397. printf("\n");
  398. }
  399. return 0;
  400. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement