StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
prepareFile.cc
1 /***************************************************************************
2  *
3  * $Id: prepareFile.cc,v 1.1 1999/02/17 12:38:48 ullrich Exp $
4  *
5  * Author: Thomas Ullrich, August 1998
6  ***************************************************************************
7  *
8  * Description:
9  *
10  ***************************************************************************
11  *
12  * $Log: prepareFile.cc,v $
13  * Revision 1.1 1999/02/17 12:38:48 ullrich
14  * Initial Revision
15  *
16  **************************************************************************/
17 #include <string>
18 #include <fstream.h>
19 #include <cstdlib>
20 #include <unistd.h>
21 #include <stdio.h>
22 #include <utility>
23 #include <list>
24 #include <vector>
25 #include <stdexcept>
26 
27 //#define DEBUG
28 #define PR(x) cout << #x << " = " << (x) << endl;
29 
30 struct ClassInfo {
31  ClassInfo();
32  string name;
33  size_t bodyStart;
34  size_t bodyEnd;
35  bool correct;
36  void print();
37 };
38 
39 ClassInfo::ClassInfo() : correct(false), bodyStart(0), bodyEnd(0) {}
40 
41 void ClassInfo::print()
42 {
43  cout << "name = " << name << endl;
44  cout << "bodyStart = " << bodyStart << endl;
45  cout << "bodyEnd = " << bodyEnd << endl;
46 }
47 
48 size_t ccount(string& s, char c)
49 {
50  size_t n = 0;
51  for (int i=0; i<s.size(); i++)
52  if (s[i] == c) n++;
53  return n;
54 }
55 
56 int main(int argc, char* argv[])
57 {
58  long i, j, k;
59 
60  if (argc < 2) {
61  cerr << "Usage: " << argv[0] << " file ..." << endl;
62  return 2;
63  }
64 
65  vector<string> inputFileList;
66  for (i=1; i<argc; i++)
67  inputFileList.push_back(argv[i]);
68 
69 
70  for (int iFile=0; iFile<inputFileList.size(); iFile++) {
71 
72  string inputfile = inputFileList[iFile];
73 
74  if (access(inputfile.c_str(), R_OK) != 0) {
75  cerr << argv[0] << ": cannot access file " << inputfile << endl;
76  continue;
77  }
78 
79  cout << "preparing file " << inputfile << " .";
80 
81  string tempfile1(tempnam(".",0)); tempfile1 += ".cc";
82  string tempfile2(tempnam(".",0)); tempfile2 += ".cc";
83  string command;
84 #if defined(DEBUG)
85  PR(tempfile1);
86  PR(tempfile2);
87 #endif
88 
89  //
90  // Remove tabs and comment #include statements
91  //
92  command = "expand ";
93  command += inputfile;
94  command += "| sed 's/\\#.*include/\\/\\/&/g' > ";
95  command += tempfile1;
96 #if defined(DEBUG)
97  cout << command << endl;
98 #endif
99  system(command.c_str());
100  cout << '.'; cout.flush();
101 
102  //
103  // Run the preprocessor and eliminate #line statements
104  // (they contain the name of the $TMPFILE file)
105  //
106  command = "g++ -E ";
107  command += tempfile1;
108  command += " | grep -v ";
109  command += tempfile1;
110  command += " > ";
111  command += tempfile2;
112 #if defined(DEBUG)
113  cout << command << endl;
114 #endif
115  system(command.c_str());
116  cout << '.'; cout.flush();
117 
118  //
119  // Now in C++,
120  // read the whole file in one string
121  // and indent everything in a way that
122  // further processing is easy.
123  //
124  long len, pos;
125  string line;
126  string bigLine;
127  char c;
128  ifstream ifs(tempfile2.c_str());
129  while (ifs.good()) {
130  getline(ifs, line, '\n');
131  if (ifs.eof()) break;
132  if (line.empty()) continue; // skip empty lines
133  line += ' ';
134  for (i=0; i<line.size(); i++) {
135  c = line[i];
136  switch(c) {
137  case ';':
138  bigLine += ";\n";
139  break;
140  case '{':
141  bigLine += "\n{\n";
142  break;
143  case '}':
144  if (i+1 < line.size() && line[i+1] == ';') {
145  bigLine += "\n};\n";
146  i++;
147  }
148  else
149  bigLine += "\n}\n";
150  break;
151  case '\t':
152  break;
153  default:
154  bigLine += c;
155  break;
156  }
157  }
158  }
159  ifs.close();
160  cout << '.'; cout.flush();
161  pos = 0;
162  while(pos < bigLine.size()) {
163  pos = bigLine.find("public:", pos);
164  if (pos != string::npos) {
165  bigLine.replace(pos, 7 , "public:\n");
166  pos += 7;
167  }
168  else
169  break;
170  }
171  pos = 0;
172  while(pos < bigLine.size()) {
173  pos = bigLine.find("private:", pos);
174  if (pos != string::npos) {
175  bigLine.replace(pos, 8 , "private:\n");
176  pos += 8;
177  }
178  else
179  break;
180  }
181  pos = 0;
182  while(pos < bigLine.size()) {
183  pos = bigLine.find("protected:", pos);
184  if (pos != string::npos) {
185  bigLine.replace(pos, 10 , "protected:\n");
186  pos += 10;
187  }
188  else
189  break;
190  }
191  cout << '.'; cout.flush();
192 
193  //
194  // Remove inline keyword
195  //
196  pos = 0;
197  while(pos < bigLine.size()) {
198  pos = bigLine.find("inline ", pos);
199  if (pos != string::npos) {
200  bigLine.erase(pos, 7);
201  }
202  else
203  break;
204  }
205  cout << '.'; cout.flush();
206 
207  //
208  // Fix some bad coding styles
209  //
210  pos = 0;
211  while(pos < bigLine.size()) {
212  pos = bigLine.find(":", pos);
213  if (pos != string::npos) {
214  bigLine.replace(pos, 1, " : ");
215  pos += 3;
216  }
217  else
218  break;
219  }
220  cout << '.'; cout.flush();
221 
222  //
223  // Remove double blanks
224  //
225  pos = 0;
226  bool reset = false;
227  while(true) {
228  pos = bigLine.find(" ", pos);
229  if (pos != string::npos) {
230  bigLine.erase(pos, 1);
231  reset = false;
232  }
233  else {
234  if (reset) break;
235  }
236  if (pos >= bigLine.size()) {
237  reset = true;
238  pos = 0;
239  }
240  }
241  cout << '.'; cout.flush();
242 
243  //
244  // Merge into line vector
245  //
246  vector<string> allLines;
247  line.erase();
248  bool beginLine = true;
249  for (i=0; i<bigLine.size(); i++) {
250  c = bigLine[i];
251  switch(c) {
252  case ' ':
253  if (!beginLine)
254  line += c;
255  break;
256  case '\n':
257  if (!line.empty()) {
258  line += c;
259  allLines.push_back(line);
260  }
261  line.erase();
262  beginLine = true;
263  break;
264  default:
265  line += c;
266  beginLine = false;
267  break;
268  }
269  }
270  bigLine.erase();
271  cout << '.'; cout.flush();
272 
273 #if defined(DEBUG)
274  copy(allLines.begin(), allLines.end(), ostream_iterator<string>(cout));
275 #endif
276 
277 
278  //
279  // Some cosmetics
280  //
281  for (i=0; i<allLines.size(); i++) {
282  line = allLines[i];
283  pos = line.find("operator ",0);
284  if (pos != string::npos) line.replace(pos, 9 , "operator");
285  pos = line.find("< class",0);
286  if (pos != string::npos) line.replace(pos, 7 , "<class");
287  pos = line.find(" < ",0);
288  if (pos != string::npos) line.replace(pos, 3 , "<");
289  pos = line.find(" > ",0);
290  if (pos != string::npos) line.replace(pos, 3 , "> ");
291  pos = line.find(" >",0);
292  if (pos != string::npos) line.replace(pos, 2 , ">");
293  pos = line.find(" & ",0);
294  if (pos != string::npos) line.replace(pos, 3 , "& ");
295  pos = line.find("template <",0);
296  if (pos != string::npos) line.replace(pos, 10 , "template<");
297  pos = line.find("private :",0);
298  if (pos != string::npos) line.replace(pos, 9 , "private:");
299  pos = line.find("protected :",0);
300  if (pos != string::npos) line.replace(pos, 11 , "protected:");
301  pos = line.find("public :",0);
302  if (pos != string::npos) line.replace(pos, 8 , "public:");
303  pos = line.find(": :",0);
304  if (pos != string::npos) line.replace(pos, 3 , "::");
305  pos = line.find(" :: ",0);
306  if (pos != string::npos) line.replace(pos, 4 , "::");
307  allLines[i] = line;
308  }
309  cout << '.'; cout.flush();
310 
311  //
312  // Remove private/protected sections
313  //
314  vector<string>::iterator viter;
315  vector<string> theText;
316  bool inPrivateRegion = false;
317  bool inProtectedRegion = false;
318  for (viter = allLines.begin(); viter != allLines.end(); viter++) {
319  if (inPrivateRegion) {
320  if (viter->find("protected:") != string::npos ||
321  viter->find("public:") != string::npos ||
322  *viter == string("};\n"))
323  inPrivateRegion = false;
324  }
325  else {
326  if (viter->find("private:") != string::npos)
327  inPrivateRegion = true;
328  }
329  if (inProtectedRegion) {
330  if (viter->find("private:") != string::npos ||
331  viter->find("public:") != string::npos ||
332  *viter == string("};\n"))
333  inProtectedRegion = false;
334  }
335  else {
336  if (viter->find("protected:") != string::npos)
337  inProtectedRegion = true;
338  }
339 
340  if (!inPrivateRegion && !inProtectedRegion &&
341  *viter != string("\n") && !viter->empty())
342  theText.push_back(*viter);
343  }
344  allLines.clear();
345  cout << '.'; cout.flush();
346 
347  //
348  // Get class name(s) (if any). Includes enums.
349  //
350  vector<ClassInfo> classInfo;
351  size_t pos1, pos2;
352  for (k=0; k<theText.size(); k++) {
353  if ((pos=theText[k].rfind("class ")) != string::npos &&
354  theText[k].rfind(";") == string::npos ) { // no forward declerations
355  if (pos-1 >= 0) {
356  if (theText[k][pos-1] == '<' ||
357  theText[k][pos-1] == ',') continue;
358  }
359  if (pos-2 >= 0) {
360  if (theText[k][pos-2] == '<' ||
361  theText[k][pos-2] == ',') continue;
362  }
363  ClassInfo info;
364  pos1 = theText[k].find_first_not_of(' ', pos+5);
365  pos2 = theText[k].find_first_of(' ', pos1)-1;
366  info.name = theText[k].substr(pos1, pos2-pos1+1);
367  info.bodyStart = k+1; // '{' should be in next line
368  classInfo.push_back(info);
369  }
370  if ((pos=theText[k].find("enum ")) != string::npos) {
371  ClassInfo info;
372  pos1 = theText[k].find_first_not_of(' ', pos+4);
373  pos2 = theText[k].find_first_of(' ', pos1)-1;
374  info.name = theText[k].substr(pos1, pos2-pos1+1);
375  info.bodyStart = k+1; // '{' should be in next line
376  classInfo.push_back(info);
377  }
378  if ((pos=theText[k].find("struct ")) != string::npos) {
379  ClassInfo info;
380  pos1 = theText[k].find_first_not_of(' ', pos+4);
381  pos2 = theText[k].find_first_of(' ', pos1)-1;
382  info.name = theText[k].substr(pos1, pos2-pos1+1);
383  info.bodyStart = k+1; // '{' should be in next line
384  classInfo.push_back(info);
385  }
386  }
387  cout << '.'; cout.flush();
388 
389  //
390  // Find position where class body ends '};'
391  // Caution here, classes could be nested
392  //
393  vector<size_t> tmp;
394  for (k = 0; k<theText.size(); k++) {
395  if (theText[k].find("};") != string::npos) {
396  tmp.push_back(k);
397  }
398  }
399 #if defined(DEBUG)
400  PR(tmp.size());
401  PR(classInfo.size());
402 #endif
403  if (tmp.size() != classInfo.size()) {
404  cout << " . error" << endl;
405  cout << argv[0] << ": tmp.size() != classInfo.size()" << endl;
406  remove(tempfile1.c_str());
407  remove(tempfile2.c_str());
408  theText.clear();
409  continue;
410  }
411 
412  // Which is which -> look for closest distance first;
413  int dist, minDist;
414  pair<size_t, size_t> minPair;
415  int nMatches = 0;
416 
417  while (nMatches != classInfo.size()) {
418  minDist = theText.size();
419  for (k=0; k<tmp.size(); k++) {
420  if (tmp[k] == 0) continue; // is flagged as used
421  for (i=0; i<classInfo.size(); i++) {
422  if (classInfo[i].correct) continue; // has already a partner
423  dist = tmp[k]-classInfo[i].bodyStart;
424  if (dist < 0) continue;
425  if (dist < minDist) {
426  minDist = dist;
427  minPair.first = k; // position of end-of-body
428  minPair.second = i; // index of class
429  }
430  }
431  }
432  classInfo[minPair.second].bodyEnd = tmp[minPair.first];
433  classInfo[minPair.second].correct = true; // flag as correct
434  tmp[minPair.first] = 0; // flag used
435  nMatches++;
436  }
437  cout << '.'; cout.flush();
438 #if defined(DEBUG)
439  for (i=0; i<classInfo.size(); i++) {
440  classInfo[i].print();
441  }
442 #endif
443 
444  //
445  // Next is to remove all bodies, except the class bodies
446  // and the namespaces.
447  // Add a semicolon instead: definition -> declaration
448  //
449  vector<bool> markForDelete(theText.size(), false);
450  bool isStart;
451  size_t leftBrackets;
452  size_t rightBrackets;
453  for (k=0; k<theText.size(); k++) {
454  if (theText[k][0] == '{') {
455  isStart = true;
456  for (i=0; i<classInfo.size(); i++) {
457  if (classInfo[i].bodyStart == k) {
458  isStart = false;
459  break;
460  }
461  }
462  if (k-1 >= 0 &&
463  theText[k-1].find("namespace") != string::npos &&
464  theText[k-1].find("using") == string::npos) {
465  isStart = false;
466  break;
467  }
468  if (isStart) {
469  leftBrackets = rightBrackets = 0;
470  theText[k-1].insert(theText[k-1].size()-1, ";");
471  for (j=k; j<theText.size(); j++) {
472  markForDelete[j] = true;
473  // One problem here: they might be more {,} in the bodies
474  // therefore ...
475  leftBrackets += ccount(theText[j], '{');
476  rightBrackets += ccount(theText[j], '}');
477  if (j > k && leftBrackets == rightBrackets) {
478  isStart == false;
479  break;
480  }
481  }
482  }
483  }
484  }
485 #if defined(DEBUG)
486  for (k=0; k<theText.size(); k++) {
487  if (markForDelete[k]) cout << "DELETE>>>";
488  cout << theText[k];
489  }
490 #endif
491  for (k=0; k<theText.size(); k++)
492  if (markForDelete[k]) theText[k].erase();
493  cout << '.'; cout.flush();
494 
495  //
496  // Now get rid of all definitions, only declarations are needed.
497  // Do not remove them in case they are inside a class body. This
498  // could mean different things.
499  // Remove also the data member constructors. Some cleanup ...
500  //
501  bool isClassDeclaration;
502  bool isInsideClassBody;
503  for (k=0; k<theText.size(); k++) {
504  if (theText[k].find("::") != string::npos) {
505  isInsideClassBody = false;
506  for (i=0; i<classInfo.size(); i++) {
507  if (k > classInfo[i].bodyStart && k < classInfo[i].bodyEnd)
508  isInsideClassBody = true;
509  }
510  if (!isInsideClassBody) theText[k].erase();
511  }
512  if (theText[k].find("extern \"C\"") != string::npos) theText[k].erase();
513  pos = theText[k].find(" ;",0);
514  if (pos != string::npos) theText[k].replace(pos, 2 , ";");
515  isClassDeclaration = false;
516  for (i=0; i<classInfo.size(); i++) {
517  if (classInfo[i].bodyStart-1 == k)
518  isClassDeclaration = true;
519  }
520  if (!isClassDeclaration) {
521  pos = theText[k].find(" : ",0);
522  if (pos != string::npos) {
523  theText[k].erase(pos, theText[k].size()-pos);
524  line += '\n';
525  }
526  }
527  }
528  cout << '.'; cout.flush();
529 
530  //
531  // Get basename of input file
532  //
533  pos = inputfile.rfind('/');
534  if (pos != string::npos)
535  inputfile.erase(0, pos+1);
536 
537  string keywordFile(inputfile); keywordFile += ".keywords";
538  string outFile(inputfile); outFile += ".out";
539 
540  //
541  // Write out the results
542  //
543  ofstream keyfs(keywordFile.c_str());
544  ofstream outfs(outFile.c_str());
545  for (k=0; k<theText.size(); k++) {
546  if (!theText[k].empty() && theText[k] != "\n")
547  outfs << theText[k];
548  }
549  for (i=0; i<classInfo.size(); i++) keyfs << classInfo[i].name << endl;
550  cout << '.'; cout.flush();
551 
552  //
553  // Remove temporary files
554  //
555  remove(tempfile1.c_str());
556  remove(tempfile2.c_str());
557 
558  theText.clear();
559 #if defined(DEBUG)
560  copy(theText.begin(), theText.end(), ostream_iterator<string>(cout, "\n"));
561 #endif
562  cout << ". done" << endl;
563  }
564  return 0;
565 }