-
Notifications
You must be signed in to change notification settings - Fork 0
/
DepGraph.cpp
147 lines (132 loc) · 4.59 KB
/
DepGraph.cpp
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// Eli Simmonds
// CS315 Project04
// DepGraph.cpp
#include "DepGraph.hpp"
#include "GraphNode.hpp"
DepGraph::DepGraph( std::string name ) {
_fileToMake = name;
_targetToMake = " ";
firstTarget = nullptr;
_tree = new MakeTree();
}
void DepGraph::print() { // just for testing
_tree->print();
}
void DepGraph::parseDepGraph() {
Reader *reader = new Reader(_fileToMake); // reader created with makefile
Token token = readAndProcessDependencyPair( reader ); // get first spot
while ( !token.isEOF() ) {
token = readAndProcessDependencyPair( reader ); // start building data structures
} // and save the current spot into token
}
bool DepGraph::isCyclic() {
return isCyclic(firstTarget);
}
bool DepGraph::isCyclic( GraphNode *p ) {
if (p->onPath()) // check initial on path
return true;
p->onPath( true ); // set true
for (int i = 0; i < p->numDependentNodes(); i++) { // recursively check if its cyclic
if (isCyclic(p->dependentNodes()->at(i))) {
std::cout << p->dependentNodes()->at(i)->getName() << ' '; // print cyclic node
return true; } // return
}
p->onPath( false ); // no dependent nodes have cycles
return false; // done
}
void DepGraph::runMake() {
for (int i = 0; i < firstTarget->numDependentNodes(); i++) {
runMake(( *(firstTarget->dependentNodes()))[i]); // run each node
}
runMake(firstTarget); // finally compile it all
}
void DepGraph::runMake( GraphNode *p ) {
bool run = false;
long time;
long depTime;
timestamp(p->getName().c_str(), &time); // time
p->setTimestamp(time); // set timestamp
for (int i = 0; i < p->numDependentNodes(); i++) {
timestamp(p->dependentNodes()->at(i)->getName().c_str(), &depTime); // dependent time
p->dependentNodes()->at(i)->setTimestamp(depTime); // set time for dep
if (depTime > time) { // does it need to be compiled again?
run = true;
}
}
if (run) { // needs to be recompiled
p->runCommand();
}
else if (p->getName() == firstTarget->getName()) { // all set!
std::cout << p->getName() << " is up to date" << std::endl;
}
}
bool DepGraph::timestamp( const char *fname, long *time ) {
struct stat finfo; // local timestamp funct.
if (stat( fname, &finfo ) == 0) {
*time = finfo.st_mtime;
return true; }
else if (errno == ENOENT) {
*time = -1L;
return true; }
else
return false;
}
Token DepGraph::readAndProcessDependencyPair( Reader *reader ) {
GraphNode *targetNode;
GraphNode *dependentNode;
Token target = reader->getToken(); // get intial token
if( target.isEOF() ) { // check if end of file.
return target; // crap out
}
if( ! target.isName() ) { // error checking
std::cout << "The first token of a dependency line should be a name-token.\n";
exit(1);
}
if (_tree->find(target.getName()) == nullptr) { // check if in list
targetNode = new GraphNode(target.getName()); // not in list. lets create it
targetNode->isATarget(true); // yep its a target
_tree->insert(targetNode); // throw it in the tree as makenode
}
if (firstTarget == nullptr) { // is it empty?
firstTarget = targetNode; // make it the first node
}
else {
targetNode = _tree->find(target.getName()); // check if it's in the tree and save node
// targetNode->print(); // print what we found
}
Token colon = reader->getToken();
if( ! colon.isColon() ) { // error checking makefile
std::cout << "Missing colon character on the dependency line.\n";
exit(1);
}
// everything is set. time to get dependencies.
Token token = reader->getToken();
do {
if (_tree->find(token.getName()) != nullptr) { // check if it's in there
dependentNode = _tree->find(token.getName()); // if its in save
targetNode->addDependentNode(dependentNode); // and insert into the vector
}
else {
dependentNode = new GraphNode(token.getName()); // not in there yet
_tree->insert(dependentNode); // insert now
targetNode->addDependentNode(dependentNode); // add into vector as well
}
token = reader->getToken(); // get next name
} while( token.isName() ) ;
if( ! token.isEOL() ) { // error checking
std::cout << "Dependency line contains a non-name token.\n";
exit(1);
}
if (targetNode->isATarget()) { // if its a target then set the timestamp
targetNode->setTimestamp(-1);
}
Token command = reader->getToken(); // lets get the final line and save to token
if (command.isEOF()) // check if we're at the end of file
return command; // yep let's return the token
if (!command.isCommand()) { // error checking
std::cout << "DepGraph: No Command found" << std::endl;
exit(1);
}
targetNode->setCommand(command.getCommand()); // it's a command. set it to the target.
return token; // return current token
}