Jpp  17.0.0
the software that should make you happy
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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 
19 namespace {
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  */
285 int 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 }
Utility class to parse command line options.
Definition: JParser.hh:1500
int main(int argc, char *argv[])
Definition: Main.cc:15
bool is_double_quoted(const std::string &value)
Check quotation.
std::string getPath(const std::string &file_name)
Get path, i.e. part before last JEEP::PATHNAME_SEPARATOR if any.
Definition: JeepToolkit.hh:148
string outputFile
is
Definition: JDAQCHSM.chsm:167
#define ASSERT(A,...)
Assert macro.
Definition: JMessage.hh:90
#define make_field(A,...)
macro to convert parameter to JParserTemplateElement object
Definition: JParser.hh:1961
bool is_valid(const json &js)
Check validity of JSon data.
std::istream & getline(std::istream &in, JString &object)
Read string from input stream until end of line.
Definition: JString.hh:478
int debug
debug level
Definition: JSirene.cc:66
$WORKDIR driver txt done cat $WORKDIR driver txt<< EOFprocess ${DATAFILTER}$FILTER_HOST csh-c '(setenv ROOTSYS $ROOTSYS &&source $JPP_DIR/setenv.csh $JPP_DIR &&(JDataFilter-H\$SERVER\$-M\$LOGGER\$-d $DEBUG-u ${DATAFILTER}-P $PORT</dev/null > &/dev/null &))';process ${DATAWRITER}$WRITER_HOST csh-c '(setenv ROOTSYS $ROOTSYS &&source $JPP_DIR/setenv.csh $JPP_DIR &&(JDataWriter-H\$SERVER\$-M\$LOGGER\$-d $DEBUG-u ${DATAWRITER}</dev/null > &/dev/null &))';print enterevent ev_init{RC_CMD}event ev_reset{RC_CMD}event ev_init{RC_CMD}event ev_configure{RC_DFLTR%<$WORKDIR/ev_configure_datafilter.txt > RC_DOM<$WORKDIR/ev_configure_domsimulator.txt > RC_DWRT path
print
Definition: JConvertDusj.sh:44
General purpose messaging.
#define FATAL(A)
Definition: JMessage.hh:67
Utility class to parse command line options.
System auxiliaries.
void copy(const Head &from, JHead &to)
Copy header from from to to.
Definition: JHead.cc:139
then echo Creating output directory
Definition: JTuneHV.sh:83
then fatal Wrong number of arguments fi set_variable DETECTOR $argv[1] set_variable INPUT_FILE $argv[2] eval JPrintDetector a $DETECTOR O IDENTIFIER eval JPrintDetector a $DETECTOR O SUMMARY JAcoustics sh $DETECTOR_ID source JAcousticsToolkit sh CHECK_EXIT_CODE typeset A EMITTERS get_tripods $WORKDIR tripod txt EMITTERS get_transmitters $WORKDIR transmitter txt EMITTERS for EMITTER in
Definition: JCanberra.sh:46
#define DEBUG(A)
Message macros.
Definition: JMessage.hh:62