Jpp test-rotations-new
the software that should make you happy
Loading...
Searching...
No Matches
JDependencies.cc
Go to the documentation of this file.
1#include <string>
2#include <iostream>
3#include <fstream>
4#include <sstream>
5#include <iomanip>
6#include <cstdlib>
7#include <vector>
8#include <set>
9#include <map>
10#include <dirent.h>
11
13#include "JLang/JLangToolkit.hh"
14
15#include "Jeep/JParser.hh"
16#include "Jeep/JMessage.hh"
17
18
19namespace {
20
21 static const char WILDCARD = '%'; //!< file name wild card
22
23 static const char* const INCLUDE_DIRECTIVE = "#include"; //!< C++ include directive
24 static const char* const NAMESPACE_DIRECTIVE = "namespace"; //!< C++ namespace directive
25 static const char* const INCLUDE_EXTENSION = ".hh"; //!< Jpp include file extension
26 static const char* const SOFTWARE_DIRECTORY = "software"; //!< Jpp software directory
27
28 static const std::set<std::string> rm = //!< discard sub-directories
29 { "JMarkov" };
30
31
32 /**
33 * Auxiliary class to list dependencies of Jpp include files.
34 */
35 struct JDirectory :
36 public std::map<std::string, std::set<std::string> >
37 {
38 static const char JPP_PREFIX = 'J'; //!< Jpp file name prefix
39 static const char DIRECTORY_SEPARATOR = '/'; //!< sub-directory
40
41
42 /**
43 * Auxiliary data structure for directory path.
44 */
45 struct path_type :
46 public std::vector<std::string>
47 {
48 /**
49 * Check validity of path.
50 *
51 * \param key key
52 * \return true if valid; else false
53 */
54 bool is_valid(const key_type& key) const
55 {
56 for (const_iterator p = this->begin(); p != this->end(); ++p) {
57
58 if (key == *p) {
59 return false;
60 }
61
62 for (const_iterator q = this->begin(); q != p; ++q) {
63 if (*p == *q) {
64 return false;
65 }
66 }
67 }
68
69 return true;
70 }
71 };
72
73
74 /**
75 * Default constructor.
76 *
77 * \param dir top-level directory
78 */
79 JDirectory(const std::string& dir = "")
80 {
81 using namespace std;
82 using namespace JPP;
83
84 const string JPP_DIR = (dir != "" ? dir : getenv("JPP_DIR"));
85 const string TOP = JPP_DIR + DIRECTORY_SEPARATOR + SOFTWARE_DIRECTORY;
86
87 for (const auto& top : ls(TOP)) {
88
89 if (top[0] == JPP_PREFIX && rm.count(top) == 0) {
90
91 const string SUB = TOP + DIRECTORY_SEPARATOR + top;
92
93 for (const auto& file : ls(SUB)) {
94
95 if (file.find(INCLUDE_EXTENSION) != string::npos) {
96
97 const string file_name = SUB + DIRECTORY_SEPARATOR + file;
98
99 ifstream in(file_name.c_str());
100
101 for (string buffer; getline(in, buffer) && buffer.find(NAMESPACE_DIRECTIVE) == string::npos; ) {
102
103 if (buffer.find(INCLUDE_DIRECTIVE) != string::npos) {
104
105 istringstream is(buffer);
106
107 string key, include_file;
108
109 is >> key >> include_file;
110
111 if (is_double_quoted(include_file) && include_file[1] == JPP_PREFIX) {
112
113 const size_t pos = include_file.find(DIRECTORY_SEPARATOR);
114
115 if (pos != string::npos) {
116
117 const string dir = include_file.substr(1, pos - 1);
118
119 if (dir != top) {
120 (*this)[top].insert(dir);
121 }
122 }
123 }
124 }
125 }
126
127 in.close();
128 }
129 }
130 }
131 }
132 }
133
134
135 /**
136 * Copy constructor.
137 *
138 * \param input directory
139 * \param key key
140 */
141 JDirectory(const JDirectory& input, const key_type& key)
142 {
143 this->copy(input, key);
144 }
145
146
147 /**
148 * Get mapped data for given key.
149 *
150 * \param key key
151 * \return mapped data
152 */
153 const mapped_type& get(const key_type& key) const
154 {
155 static const mapped_type buffer;
156
157 const_iterator p = this->find(key);
158
159 if (p != this->end())
160 return p->second;
161 else
162 return buffer;
163 }
164
165
166 /**
167 * Get circular dependency for given key.
168 *
169 * \param key key
170 * \return path
171 */
172 path_type getPath(const key_type& key) const
173 {
174 path.clear();
175
176 evaluate(key, get(key));
177
178 return path;
179 }
180
181
182 /**
183 * Check recursively mapped data for given key.
184 *
185 * \param key key
186 * \return true if valid; else false
187 */
188 bool is_valid(const key_type& key) const
189 {
190 path.clear();
191
192 return evaluate(key, get(key));
193 }
194
195
196 /**
197 * Print data conform tikz format.
198 *
199 * \param out output stream
200 */
201 inline void print(std::ostream& out) const
202 {
203 using namespace std;
204
205 for (const_iterator i = this->begin(); i != this->end(); ++i) {
206
207 out << i->first << " -> {";
208
209 for (const auto& dir : i->second) {
210 out << " " << dir << ",";
211 }
212
213 out << "}," << endl;
214 }
215 }
216
217
218 /**
219 * Print data conform tikz format.
220 *
221 * \param out output stream
222 * \param key key
223 */
224 inline void print(std::ostream& out, const JDirectory::key_type& key) const
225 {
226 JDirectory(*this, key).print(out);
227 }
228
229 private:
230 /**
231 * Recursive copy of input data.
232 *
233 * \param input directory
234 * \param key key
235 */
236 void copy(const JDirectory& input, const key_type& key)
237 {
238 (*this)[key] = input.get(key);
239
240 for (const auto& dir : input.get(key)) {
241 if (this->find(dir) == this->end()) {
242 copy(input, dir);
243 }
244 }
245 }
246
247
248 /**
249 * Check recursively mapped data for given key.
250 *
251 * \param key key
252 * \param target target data
253 * \return true if valid; else false
254 */
255 bool evaluate(const key_type& key, const mapped_type& target) const
256 {
257 if (!path.is_valid(key)) { // premature end
258 return false;
259 }
260
261 for (mapped_type::const_iterator i = target.begin(); i != target.end(); ++i) {
262
263 path.push_back(*i); // grow
264
265 if (!evaluate(key, this->get(*i))) {
266 return false;
267 }
268
269 path.pop_back(); // shrink
270 }
271
272 return true; // normal end
273 }
274
275 mutable path_type path; // internal buffer
276 };
277}
278
279
280/**
281 * \file
282 * Example program to test dependencies of include files.
283 * \author mdejong
284 */
285int main(int argc, char **argv)
286{
287 using namespace std;
288 using namespace JPP;
289
290 string outputFile;
291 string jpp;
292 string dir;
293 int debug;
294
295 try {
296
297 JParser<> zap("Example program to test dependencies of include files");
298
299 zap['o'] = make_field(outputFile) = "";
300 zap['J'] = make_field(jpp) = "";
301 zap['D'] = make_field(dir) = "";
302 zap['d'] = make_field(debug) = 3;
303
304 zap(argc, argv);
305 }
306 catch(const exception &error) {
307 FATAL(error.what() << endl);
308 }
309
310
311 const JDirectory directory(jpp);
312
313
314 if (outputFile != "") {
315
316 const size_t pos = outputFile.find(WILDCARD);
317
318 if (pos != string::npos) {
319 outputFile.replace(pos, 1, (dir != "" ? dir.c_str() : "Jpp"));
320 }
321
322 ofstream out(outputFile.c_str());
323
324 out << "\\documentclass[border=5mm]{standalone}" << endl;
325 out << "" << endl;
326 out << "\\usepackage{tikz}" << endl;
327 out << "\\usetikzlibrary{graphs, graphdrawing}" << endl;
328 out << "\\usegdlibrary{layered}" << endl;
329 out << "\\begin{document}" << endl;
330 out << "" << endl;
331 out << "\\tikz \\graph [layered layout]" << endl;
332 out << "{" << endl;
333
334 if (dir == "")
335 directory.print(out);
336 else
337 directory.print(out, dir);
338
339 out << "};" << endl;
340 out << "" << endl;
341 out << "\\end{document}" << endl;
342
343 out.close();
344 }
345
346
347 for (JDirectory::const_iterator i = directory.begin(); i != directory.end(); ++i) {
348
349 DEBUG(i->first << ": " << flush);
350
351 if (!directory.is_valid(i->first)) {
352
353 const JDirectory::path_type path = directory.getPath(i->first);
354
355 for (JDirectory::path_type::const_iterator dir = path.begin(); dir != path.end(); ++dir) {
356 DEBUG(' ' << *dir);
357 }
358 }
359
360 DEBUG(endl);
361 }
362
363 for (JDirectory::const_iterator i = directory.begin(); i != directory.end(); ++i) {
364 ASSERT(directory.is_valid(i->first), "check validity " << i->first);
365 }
366
367 return 0;
368}
string outputFile
int main(int argc, char **argv)
General purpose messaging.
#define DEBUG(A)
Message macros.
Definition JMessage.hh:62
#define ASSERT(A,...)
Assert macro.
Definition JMessage.hh:90
#define FATAL(A)
Definition JMessage.hh:67
int debug
debug level
Definition JSirene.cc:72
Utility class to parse command line options.
#define make_field(A,...)
macro to convert parameter to JParserTemplateElement object
Definition JParser.hh:2142
void print(const TH1 &h1, std::ostream &out)
Print histogram parameters.
Utility class to parse command line options.
Definition JParser.hh:1698
void copy(const Head &from, JHead &to)
Copy header from from to to.
Definition JHead.cc:163
std::string getPath(const std::string &file_name)
Get path, i.e. part before last JEEP::PATHNAME_SEPARATOR if any.
std::istream & getline(std::istream &in, JString &object)
Read string from input stream until end of line.
Definition JString.hh:478
bool is_double_quoted(const std::string &value)
Check quotation.
This name space includes all other name spaces (except KM3NETDAQ, KM3NET and ANTARES).
bool is_valid(const json &js)
Check validity of JSon data.
Target.
Definition JHead.hh:300
Auxiliary data structure to list files in directory.