-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.c
110 lines (97 loc) · 3.65 KB
/
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/**
* @author Harsh Rawat, harsh-rawat, hrawat2
* @author Sidharth Gurbani, gurbani, gurbani
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "error_handle.h"
#include "makefile_parser.h"
#include "execution_engine.h"
/**
* These are internal methods used in this main file
* */
void findMakefileTargetAndName(int argc, char *argv[], char **makefile_args);
char *findMakefile(char *name);
/**
* main method of this project.
* We parse the makefile to build an execution graph and then we execute it
* */
int main(int argc, char *argv[]) {
//makefile_args contain target_name and makefile_name
char **makefile_args = malloc(sizeof(char *) * 2);
ValidateMemoryAllocationError(makefile_args);
//Find the appropriate target and file name based on the input args
findMakefileTargetAndName(argc, argv, makefile_args);
FILE *file = fopen(makefile_args[1], "r");
if (file == NULL) {
FileOpenError(makefile_args[1], errno);
}
//Generate execution graph by calling ParseMakefile. Then check for any cyclic dependencies in the graph.
list_node *execution_graph = ParseMakefile(file);
DetectCycleInGraph(execution_graph);
//Execute the execution graph from the node which has the target name as provided (In case of NULL, we use the first rule).
ExecuteExecutionGraph(execution_graph, makefile_args[0]);
//Close the file and perform other cleanup
fclose(file);
free(makefile_args);
return 1;
}
/**
* This method is used to find the makefile name and target from the arguments passed to main
* We can pass 0,1,2 or 3 parameters. In case of incorrect number or format of parameters, we raise an error
* */
void findMakefileTargetAndName(int argc, char *argv[], char **makefile_args) {
if (argc < 1 || argc > 4)
InvalidArgumentsError("Error: Number of arguments to main should be between 0 and 3.\nExiting!");
if (argc == 1) {
//Usage as "make537"
makefile_args[0] = NULL;
makefile_args[1] = findMakefile(NULL);
} else if (argc == 2) {
//Usage as "make537 clean"
makefile_args[0] = argv[1];
makefile_args[1] = findMakefile(NULL);
} else if (argc == 3) {
//Usage as "make537 -f custom_makefile"
if (strcmp(argv[1], "-f") == 0) {
makefile_args[0] = NULL;
makefile_args[1] = findMakefile(argv[2]);
} else
InvalidArgumentsError(
"Error: If 2 arguments are being passed to main then first argument should be -f.\nExiting!");
} else if (argc == 4) {
//Usage as "make537 -f custom_makefile clean"
if (strcmp(argv[1], "-f") != 0)
InvalidArgumentsError(
"Error: If 3 arguments are being passed to main then first argument should be -f.\nExiting!");
makefile_args[0] = argv[3];
makefile_args[1] = findMakefile(argv[2]);
}
}
/**
* This method is used to find the name of appropriate makefile
* If we have passed a name then we check for its presence, else we check for makefile or Makefile
* */
char *findMakefile(char *name) {
if (name == NULL) {
char *makefile_1 = "makefile";
char *makefile_2 = "Makefile";
if (access(makefile_1, F_OK) != -1)
return makefile_1;
else if (access(makefile_2, F_OK) != -1)
return makefile_2;
else {
FileNotFoundError("makefile and Makefile", -1, NULL);
return NULL;
}
} else {
if (access(name, F_OK) == -1) {
FileNotFoundError(name, -1, NULL);
return NULL;
} else
return name;
}
}